シェルスクリプトExpress
date
Oct 24, 2019
slug
shellExpress
status
Published
tags
shell
summary
ShellスクリプトExpressメモ
type
Post
シェルスクリプト総合ガイド
目次
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"