Just another IT site ※IT系の記事は当方環境での実施内容となるため実施する場合は自己責任でお願いいたします。At Your Own Risk!! TURN BACK WHILE YOU CAN
PR

bashあれこれ

※IT系の記事は当方環境での実施内容となるため実施する場合は自己責任でお願いいたします。スクリプトはAI生成のものも多いのでコピー&ペーストの際は文字コードに注意ください!
スポンサーリンク
バッチ処理の自動化スキルは市場価値が高いです。今の自分の単価を調べてみませんか?
顧客常駐はもう嫌だ!社内SEへ転職するなら【社内SE転職ナビ】
Cursor・Claude Code・Codex AIスキルを学ぶなら
環境構築不要!AIエージェント開発を非エンジニアでも即実践【AI Agent Camp】

shebang(シバン)

#!/bin/bash
shebang(シバン)において「!」は必須です。 [1]
shebangは #! の2文字がセットで機能する特別な記号です。OSがスクリプトファイルを実行する際、この #! の後に続くパス(/bin/bash/usr/bin/python など)を見て「このプログラムを使って実行しなさい」と指示を出します。 [1]
「!」を省略して # だけにしてしまうと、単なるコメント行として無視されてしまいます。 [1]

ファイルの有無を判定してファイルがない場合にメッセージを出力する

if [ ! -e "${1}" ] ; then
echo "エラー: 引数に指定されたファイル(${1})は存在しません。" >&2
exit 1
fi
変更したポイント(解説)
  1. 変数に変数のダブルクォーテーション "${1}" を追加
      • 理由: ファイル名やパスに「半角スペース」が含まれていた場合、クォーテーションがないとシステムが複数の文字に分解してしまい、エラー(too many arguments)になります。"${1}" と囲むことで、スペース入りのファイル名にも対応できます。
  2. エラー出力(>&2)の追加
      • 理由: 正常なログ(標準出力)とエラーメッセージ(標準エラー出力)を区別するためです。他の一連のシステムやスクリプトと連携する際、エラーだけを検知しやすくなります。
  3. 終了ステータス exit 1 の指定
    • 理由: 単なる exit だけだと「正常終了(ステータス0)」として扱われてしまうことがあります。1 などの数値を指定することで、呼び出し元(他のスクリプトなど)に「異常終了した」と正しく伝えることができます。

最後のファイル名のみ表示、かつ、拡張子を取り除く

$ basename /home/hoge/hoge/hoge.txt .txt
hoge

カンマ区切り(CSVなど)のデータを1行ずつ読み込み配列に自動分割して処理する

while IFS=, read -r -a HAIRETSU は、Bashシェルスクリプトでカンマ区切り(CSVなど)のデータを1行ずつ読み込み、配列に自動分割して処理するための強力な構文です。 [1, 2]
構文の不足部分(-r オプションの追加やループのバインドなど)を補った、最も安全で一般的なテンプレートは以下の通りです。
bash
while IFS=, read -r -a HAIRETSU; do
    # 配列の各要素にアクセスして処理を記述
    echo "第1フィールド: ${HAIRETSU[0]}"
    echo "第2フィールド: ${HAIRETSU[1]}"
done < input.csv
コードは注意してご使用ください。
各要素の詳しい解説
    • IFS=,
        • IFS(Internal Field Separator:内部フィールド区切り文字)を「カンマ」に一時変更します。
        • while 内部の read コマンドに対してのみ有効な設定となるため、スクリプト全体の挙動を汚しません。

    • read
        • 標準入力または指定されたファイルからデータを1行読み込みます。

    • -r(強く推奨)
        • バックスラッシュ(\)をエスケープ文字ではなく、ただの文字列として安全に処理するためのオプションです。バグを防ぐために必ず付与してください

    • -a HAIRETSU
        • 読み込んだ行を IFS(カンマ)で分割し、HAIRETSU という名前の配列にインデックス順(0, 1, 2…)で格納します。 [1, 2, 3, 4, 5]


応用・実践パターン
1. カンマ区切りの文字列を直接分解する(ヒアストリング)
ファイルからではなく、変数に入っているカンマ区切りの文字列を配列に展開したい場合は、<<<(ヒアストリング)を使用します。 [1]
bash
data="リンゴ,バナナ,オレンジ,ブドウ"

IFS=, read -r -a fruits_array <<< "$data"

# 特定の要素や全体の個数を出力
echo "${fruits_array[1]}"    # 出力: バナナ
echo "${#fruits_array[@]}"   # 出力: 4 (配列の全要素数)
コードは注意してご使用ください。
2. 配列の全要素をループで処理する
列数が固定されていないCSVなどを処理する場合、for ルループと組み合わせることで全フィールドを動的に処理できます。 [1]
bash
while IFS=, read -r -a HAIRETSU; do
    echo "--- 新しい行の処理 ---"
    for item in "${HAIRETSU[@]}"; do
        echo "データ要素: $item"
    done
done < input.csv
コードは注意してご使用ください。

注意点:データ内の空白について
IFS=, と指定した場合、カンマの直後にあるスペース(例: aaa, bbb, ccc)も文字としてそのまま配列( bbb)に含まれます。スペースを自動でトリミングしたい場合は、IFS=', ' のようにカンマと半角スペースの両方を区切り文字として指定してください。 [1]
もし特定のCSVファイルや、実現したい処理のゴールがあれば教えてください。最適なコード例をご案内します。

引数で与えたカンマ区切りCSVファイル内のデータを1行ずつ読み込み指定した複数の変数に読み込む

while IFS=',' read -r HENSU1 HENSU2 HENSU3 
do 
  echo "${HENSU1}${HENSU2}${HENSU3}" 
  sleep 1 
done < "${1}"

exprでループ中でカウントアップする

while ループの中で行い、データがある分だけ「1, 2, 3…」とカウントアップしていきたい場合は、以下のように記述します。
count=0

while IFS=, read -r -a HAIRETSU; do
    # ループが回るたびに count を +1 する
    count=`expr ${count} + 1`
    
    echo "現在 ${count} 行目を処理中: ${HAIRETSU}"
done < input.csv

echo "最終的な総行数: ${count}"

printfで0埋めした数字を変数に代入する

X=`printf "%02d" 1`
echo $X
01

if~fiの中で直前で実行されたコマンドがエラーとなったらエラーメッセージを出力して残りの処理をSKIPする

if [ ${?} -ne 0] ;then
  echo "異常終了しました。残りの処理をスキップして、次の回へ強制的に進みます。"
  continue
fi
echo “”の中は変数の使用も可能
シェルスクリプト(Bashなど)の forwhile ループ内で if ... fi を使う場合、continue の有無によって条件に一致した後の処理順序(ループをスキップするかどうか)が変わります
具体的な違いは以下の通りです。
1. continueない 場合
条件に合致してもそのまま処理が継続され、その後のすべてのコマンドが通常通り実行されます。
bash
for i in 1 2 3 4
do
    if [ $i -eq 2 ]; then
        echo "スキップせず処理を続行: $i"
    fi
    echo "ループ内の後続処理: $i"
done
コードは注意してご使用ください。
【実行結果】
text
ループ内の後続処理: 1
スキップせず処理を続行: 2
ループ内の後続処理: 2
ループ内の後続処理: 3
ループ内の後続処理: 4
コードは注意してご使用ください。
2. continueある 場合
条件に合致すると continue が実行され、その回のループ内の残りの処理をスキップして、次の回へ強制的に進みます。
bash
for i in 1 2 3 4
do
    if [ $i -eq 2 ]; then
        echo "ここでスキップします"
        continue
    fi
    echo "ループ内の後続処理: $i"
done
コードは注意してご使用ください。
【実行結果】
text
ループ内の後続処理: 1
ここでスキップします
ループ内の後続処理: 3
ループ内の後続処理: 4
コードは注意してご使用ください。
まとめ
特定の条件のときだけ「ループ内の以降の処理を行わずに、次の周回(次のデータ)に移りたい」場合は continue を使います。条件に当てはまる場合でも通常通り最後まで処理を行わせたい場合は不要です。 [1]

if~fiの中でファイルがある場合にメッセージを出力して残りの処理をSKIPする

if [ -e ./hoge.txt] ;then   
   echo "ファイルがあるため、残りの処理をスキップして、次の回へ強制的に進みます。"   
continue 
fi

ある配列を入れた変数の第3フィールド以降を別の配列に挿入する

HAIRETSU2=("${HAIRETSU1[@]:3}"

「配列 HAIRETSU1 の3番目(4番目の要素)以降のすべてのデータを、新しい配列 HAIRETSU2 にコピーする」という意味になります(配列のスライス処理)。

各要素の詳しい意味
    • ${HAIRETSU1[@]}
        • 配列 HAIRETSU1 の「すべての要素」を、スペースや特殊文字を維持したまま安全に展開します。
    • :3(ここがポイント)
        • 「インデックス 3(4番目の要素)から後ろすべて」 という範囲指定(スライス)です。
        • 配列の番号は 0 から始まるため、0(1番目)、1(2番目)、2(3番目)を除外し、3(4番目)以降を丸ごと取り出します。
    • HAIRETSU2=( ... )
        • 取り出した要素を使って、新しく HAIRETSU2 という名前の配列を作成・代入しています。
💡 具体例で見るデータの動き
CSVの1行が aa,bb,cc,dd,ee だった場合、これまでのコードで HAIRETSU1 配列には以下のように格納されています。
インデックス 0 1 2 3 4
データ aa bb cc dd ee
ここで HAIRETSU2=("${HAIRETSU1[@]:3}") を実行すると、01 と 2aabb と cc)が無視され、dd, ee だけの新しい配列 HAIRETSU2 が作られます。
タイトルとURLをコピーしました