シェルスクリプトを書くときに私がすることのほとんどは、Python、Matlabなどの他のモジュールからI / Oをラップすることです。この目的のために、私は通常、入力/出力パスを持つテキストファイルまたは同様の性質のファイルを使用します。私は利用可能なファイルから1行を読む方法を知っています。
for file in $(cat $1);
do
code using $file
done
しかし、両方のファイルの同じ行を使用して作業を実行するにはどうすればよいですか? Javaに似ています。
while((line1 = file1.readLine()) != null) {
line2 = file2.readLine();
//do something with both lines...
}
Bashでこれを行う標準的な方法は何ですか?
答え1
exec 3<file1
exec 4<file2
while read line1 <&3 && read line2 <&4
do
echo "line1=$line1 and line2=$line2"
done
exec 3<&-
exec 4<&-
議論する
上記では、入力行から先行スペースと末尾スペースを削除しました。このスペースを維持するには、
read …
次のように置き換えます。IFS= read …
上記では、入力のバックスラッシュはエスケープ文字として解釈されます。これをしたくない場合は、次のよう
read …
に交換してください。read -r …
read line1 <&3
line1
ファイル記述子 3 から読み込みます。これは次のように等しく書くこともできますread -u3 line1
。このような声明には
for file in $(cat $1);
知っておくべきいくつかの問題があります。シェルはファイルの内容にトークン化されたパス名拡張を適用するため、予期しない限りさまざまなエラーが発生する可能性があります。
選ぶ
while read line1 <&3 && read line2 <&4
do
echo "line1=$line1 and line2=$line2"
done 3<file1 4<file2
答え2
ファイルの行を繰り返すには、次のようにします。
while IFS= read -r line; do
echo "read $line"
done <input-file
複数のファイルを繰り返すには、別のファイル記述子でそのファイルを開きます(参照追加のファイル記述子はいつ使用されますか?)。
while IFS= read -r line1 <&8 || IFS= read -r line2 <&9; do
echo "read '$line1' from file 1 and '$line2' from file 2"
done 8<input-file1 9<input-file2
最長ファイルと一致するように、空行でread <&8 || read <&9
最短ファイルを完成させます。 2つのファイルのいずれかの終わりに達したらすぐに終了するには、代わりに&&
を使用します||
。すべてのケースを検出するには、個別に戻りコードを確認してください。
{
while
IFS= read -r line1 <&8; empty1=$?
IFS= read -r line2 <&9; empty2=$?
[ "$empty1" -ne 0 ] && [ "$empty2" -ne 0 ]
do
echo "read '$line1' from file 1 and '$line2' from file 2"
done
if [ "$empty1" -ne 0 ]; then
echo "Finishing processing file 1"
…
fi
if [ "$empty2" -ne 0 ]; then
echo "Finishing processing file 2"
…
fi
} 8<input-file1 9<input-file2
あるいは、両方のファイルを一緒にリンクすることもできます。これpaste
これにはコマンドが便利です。デフォルトでは、タブごとに行を区切って(-d
別の区切り文字を選択するには渡します)、空白行でファイルを完成します。ファイルにタブ文字が含まれていない場合、入力行は明確に区別されます。
tab=$(printf \\t)
paste input-file1 input-file2 |
while IFS=$tab read -r line1 line2; do … done
シェルはテキスト処理速度がそれほど速くはありません。中大型入力には、より専門的なツールが最も適しています。前処理を使用すると、paste
後処理のために2つのファイルを簡単に圧縮できます。行を読み取るときにさらに制御が必要な場合、awkはそのコマンドを使用してこれを実行できますgetline
(シェルのように)。read