テキストファイルを 1 行だけ読み込む
read
コマンドは、ユーザからの入力を 1 行取得するために使用できますが、ファイルからの入力を 1 行読み込むのにも使用できます。
#!/bin/bash
read line < input.txt
echo "$line"
AAA 100
BBB 200
CCC 300
$ ./sample.sh
AAA 100
これだけだとあまり役に立たないので、通常は次のように while
ループを組み合わせて、すべての行を読み出します。
テキストファイルから 1 行ずつ読み込む
read
コマンドと while
ループを組み合わせると、テキストファイルのすべての行を 1 行ずつ処理できます。
#!/bin/bash
while read line; do
echo "$line"
done < input.txt
AAA 100
BBB 200
CCC 300
$ ./sample.sh
AAA 100
BBB 200
CCC 300
☝️ ワンポイント
echo
のパラメータ "$line"
をダブルクォートで囲んでいることに注意してください。
こうすることで、1 行分の文字列を、ひとつのパラメータとして渡すことができます。
ダブルクォートで囲まないと、echo AAA 100
のように、2 つのパラメータが渡されたかのように処理されてしまうため、連続するスペースが 1 つのスペースに置き換えられて出力されてしまいます。行頭のスペースが消えてしまうのを防ぐ
例えば、下記のように行頭がインデントされたテキストファイルを読み込むとします。
・カテゴリA
・カテゴリA-1
・カテゴリA-2
・カテゴリB
・カテゴリB-1
・カテゴリB-2
このファイルを次のように読み込むと、行頭のスペースが削除されてしまします。
#!/bin/bash
while read line; do
echo "$line"
done < input.txt
$ ./sample.sh
・カテゴリA
・カテゴリA-1
・カテゴリA-2
・カテゴリB
・カテゴリB-1
・カテゴリB-2
行頭のスペースをそのまま表示したい場合は、次の例のように、組み込み変数 IFS
を空文字にセットしてから処理するようにします。
変更した IFS
の値は、最後に行儀よく元の値に戻してあげてください(source
コマンドなどでスクリプトを読み込んだときに、呼び出し元シェルの IFS
の値が変更されたままになってしまうのを防ぐため)。
#!/bin/bash
old_ifs=$IFS
IFS=''
while read line; do
echo "$line"
done < input.txt
IFS=$old_ifs
$ ./sample.sh
・カテゴリA
・カテゴリA-1
・カテゴリA-2
・カテゴリB
・カテゴリB-1
・カテゴリB-2
IFS
特殊変数に関しての詳細は、man bash
を参照してください。
IFS
は内部的な文字列のセパレート処理に使われるキャラクター群を保持しています。