シェルスクリプトExpress

date
Oct 24, 2019
slug
shellExpress
status
Published
tags
shell
summary
ShellスクリプトExpressメモ
type
Post
 

シェルスクリプト総合ガイド

目次

  1. 基本構文
  1. 変数と定数
  1. 条件分岐
  1. ループ処理
  1. 関数定義
  1. ファイル操作
  1. 入力処理
  1. ベストプラクティス
  1. 実践的なスクリプト例

1. 基本構文

1.1 スクリプトの基本構造

#!/bin/bash set -euo pipefail # 定数定義 readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # メイン処理 main() { echo "処理開始" } main "$@"

1.2 コメント

# 1行コメント : ' 複数行 コメント '

2. 変数と定数

2.1 変数定義

# 通常の変数 name="John" age=25 # readonly(定数) readonly MAX_TRIES=3 # local変数(関数内) local temp_var="一時的な値" # 配列 fruits=("apple" "banana" "orange") echo "${fruits[0]}" # apple echo "${fruits[@]}" # 全要素 # 連想配列 declare -A colors colors["red"]="#FF0000" colors["blue"]="#0000FF"

2.2 変数操作

# 変数展開 echo "Hello, $name" echo "Path: ${PATH}" # 配列長 echo "${#fruits[@]}" # サブストリング echo "${string:0:5}" # 最初の5文字 # デフォルト値 echo "${undefined_var:-default}"

3. 条件分岐

3.1 if文

# 数値比較 if ((number < 10)); then echo "10未満" elif ((number < 20)); then echo "20未満" else echo "20以上" fi # 文字列・ファイル比較 if [[ "$string" == "value" ]]; then echo "一致" fi if [[ -f "$file" ]]; then echo "ファイルが存在" fi

3.2 case文

case "$fruit" in "apple") echo "リンゴ" ;; "banana"|"orange") echo "バナナまたはオレンジ" ;; *) echo "その他" ;; esac

3.3 比較演算子

# 数値比較 (( )) # -eq: 等しい # -ne: 等しくない # -gt: より大きい # -lt: より小さい # 文字列比較 [[ ]] # ==: 等しい # !=: 等しくない # =~: 正規表現マッチ # ファイルテスト # -f: 通常ファイル # -d: ディレクトリ # -r: 読み取り可能 # -w: 書き込み可能 # -x: 実行可能

4. ループ処理

4.1 forループ

# 範囲指定 for i in {1..5}; do echo "$i" done # 配列処理 for item in "${array[@]}"; do echo "$item" done # C形式 for ((i=0; i<5; i++)); do echo "$i" done

4.2 whileループ

# 条件付きループ while ((count < 5)); do echo "$count" ((count++)) done # ファイル読み込み while IFS= read -r line; do echo "$line" done < "file.txt"

5. 関数定義

5.1 基本的な関数

function_name() { local param1=$1 local param2=$2 echo "Result" return 0 } # 呼び出し result=$(function_name arg1 arg2)

5.2 エラーハンドリング

handle_error() { local -r line_no=$1 local -r error_code=$2 echo "エラー: 行 $line_no, コード $error_code" >&2 exit "$error_code" } trap 'handle_error ${LINENO} $?' ERR

6. ファイル操作

6.1 基本操作

# ファイル読み込み while IFS= read -r line; do echo "$line" done < "$file" # ファイル書き込み echo "content" > "file.txt" # 上書き echo "content" >> "file.txt" # 追記 # ファイル存在確認 if [[ -f "$file" ]]; then echo "存在します" fi

6.2 ディレクトリ操作

# ディレクトリ作成 mkdir -p "dir/subdir" # ディレクトリ削除 rm -rf "dir" # ファイル一覧 for file in *; do echo "$file" done

7. 入力処理

7.1 基本入力

# 通常入力 read -r -p "名前を入力: " name # パスワード入力(非表示) read -s -p "パスワード: " password echo # 選択肢 select choice in "Option 1" "Option 2" "Exit"; do case $choice in "Exit") break ;; *) echo "選択: $choice" ;; esac done

7.2 入力検証

# 数値チェック read -r -p "数値を入力: " num if [[ $num =~ ^[0-9]+$ ]]; then echo "有効な数値です" fi # 必須チェック read -r -p "必須項目: " required if [[ -z "$required" ]]; then echo "入力は必須です" fi

8. ベストプラクティス

8.1 変数の扱い

  • 変数は常にクォートで囲む
  • 配列要素は"${array[@]}"の形式で参照
  • localを使用してスコープを制限

8.2 エラーハンドリング

  • set -eでエラー時に終了
  • set -uで未定義変数をエラーに
  • trapでエラーをキャッチ

8.3 セキュリティ

  • 入力値の検証
  • パーミッションの適切な設定
  • 一時ファイルの安全な処理

8.4 保守性

  • 関数の適切な分割
  • 意味のある変数名
  • 十分なコメント

9. 実践的なスクリプト例

9.1 設定ファイル読み込み

#!/bin/bash set -euo pipefail load_config() { local -r config_file=$1 if [[ ! -f $config_file ]]; then echo "設定ファイルが見つかりません" >&2 return 1 } while IFS='=' read -r key value; do if [[ ! $key =~ ^[[:space:]]*# && -n $key ]]; then configs["${key// /}"]="${value// /}" fi done < "$config_file" } declare -A configs load_config "config.ini"

9.2 ログ処理

#!/bin/bash set -euo pipefail readonly LOG_FILE="/var/log/script.log" log() { local -r level=$1 shift local -r message=$* local -r timestamp=$(date '+%Y-%m-%d %H:%M:%S') echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE" } log INFO "処理開始" log ERROR "エラーが発生"

9.3 インタラクティブメニュー

#!/bin/bash set -euo pipefail show_menu() { echo "1) オプション1" echo "2) オプション2" echo "3) 終了" read -r -p "選択してください: " choice case $choice in 1) option1 ;; 2) option2 ;; 3) exit 0 ;; *) echo "無効な選択です" ;; esac } while true; do show_menu done

9.4 バックアップスクリプト

#!/bin/bash set -euo pipefail readonly BACKUP_DIR="/backup" readonly SOURCE_DIR="/source" readonly DATE=$(date '+%Y%m%d_%H%M%S') backup() { local -r target_dir=$1 local -r backup_file="${BACKUP_DIR}/backup_${DATE}.tar.gz" if [[ ! -d $target_dir ]]; then echo "ソースディレクトリが存在しません" >&2 return 1 } tar -czf "$backup_file" -C "$target_dir" . echo "バックアップ完了: $backup_file" } backup "$SOURCE_DIR"
 
If you have any questions, please contact me.