- shebang(シバン)
- ファイルの有無を判定してファイルがない場合にメッセージを出力する
- 最後のファイル名のみ表示、かつ、拡張子を取り除く
- カンマ区切り(CSVなど)のデータを1行ずつ読み込み配列に自動分割して処理する
- 引数で与えたカンマ区切りCSVファイル内のデータを1行ずつ読み込み指定した複数の変数に読み込む
- exprでループ中でカウントアップする
- printfで0埋めした数字を変数に代入する
- if~fiの中で直前で実行されたコマンドがエラーとなったらエラーメッセージを出力して残りの処理をSKIPする
- if~fiの中でファイルがある場合にメッセージを出力して残りの処理をSKIPする
- ある配列を入れた変数の第3フィールド以降を別の配列に挿入する
shebang(シバン)
#!/bin/bash
shebang(シバン)において「!」は必須です。 [1]shebangは#!の2文字がセットで機能する特別な記号です。OSがスクリプトファイルを実行する際、この#!の後に続くパス(/bin/bashや/usr/bin/pythonなど)を見て「このプログラムを使って実行しなさい」と指示を出します。 [1]
ファイルの有無を判定してファイルがない場合にメッセージを出力する
if [ ! -e "${1}" ] ; then
echo "エラー: 引数に指定されたファイル(${1})は存在しません。" >&2
exit 1
fi
変更したポイント(解説)
- 変数に変数のダブルクォーテーション
"${1}"を追加
- 理由: ファイル名やパスに「半角スペース」が含まれていた場合、クォーテーションがないとシステムが複数の文字に分解してしまい、エラー(
too many arguments)になります。"${1}"と囲むことで、スペース入りのファイル名にも対応できます。- エラー出力(
>&2)の追加
- 理由: 正常なログ(標準出力)とエラーメッセージ(標準エラー出力)を区別するためです。他の一連のシステムやスクリプトと連携する際、エラーだけを検知しやすくなります。
- 終了ステータス
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(強く推奨)-
- バックスラッシュ(
\)をエスケープ文字ではなく、ただの文字列として安全に処理するためのオプションです。バグを防ぐために必ず付与してください。
- バックスラッシュ(
-
-aHAIRETSU
応用・実践パターン
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など)のforやwhileループ内でif ... fiを使う場合、continueの有無によって条件に一致した後の処理順序(ループをスキップするかどうか)が変わります。具体的な違いは以下の通りです。1.continueが ない 場合条件に合致してもそのまま処理が継続され、その後のすべてのコマンドが通常通り実行されます。bashfor 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が実行され、その回のループ内の残りの処理をスキップして、次の回へ強制的に進みます。bashfor 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配列には以下のように格納されています。
インデックス 01234データ aabbccddeeここでHAIRETSU2=("${HAIRETSU1[@]:3}")を実行すると、0と1 と 2(aaとbb と cc)が無視され、dd,eeだけの新しい配列HAIRETSU2が作られます。
