次のようなものが含まれているテキストファイルがあります。
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
脚本を書いた
for i in `cat file`
do
echo $i
done
なんらかの理由で、スクリプトの出力はファイルを1行ずつ出力しませんが、改行だけでなくコンマで区切ります。猫または「cat xyz
のblah」がこれを行っているのはなぜですか。また、これを行わないようにするにはどうすればよいですか。私は使用できることを知っています
while read line
do
blah balh blah
done < file
しかし、私は猫や「for blah in」がUNIXコマンドの理解を深めるためにこれを行っている理由を知りたいのです。 Catのmanページは役に立たず、bashマニュアルを探したりループしたりしても答えは得られませんでした( http://www.gnu.org/software/bash/manual/bashref.html =)。よろしくお願いします。
問題はcat
にも、for
ループ自体にもありません。逆引用符を使用しています。あなたがどちらかを書くとき:
_for i in `cat file`
_
または(より良い):
_for i in $(cat file)
_
または(bash
内):
_for i in $(<file)
_
シェルはコマンドを実行し、出力を文字列としてキャプチャし、_$IFS
_の文字で単語を区切ります。 _$i
_への行入力が必要な場合は、IFS
をいじるか、while
ループを使用する必要があります。処理されるファイルが大きくなる危険性がある場合は、while
ループの方が適しています。 $(...)
を使用するバージョンとは異なり、ファイル全体を一度にメモリに読み込む必要はありません。
_IFS='
'
for i in $(<file)
do echo "$i"
done
_
_"$i"
_を囲む引用符は、一般的には良い考えです。このコンテキストでは、変更された_$IFS
_を使用すると、実際には重要ではありませんが、良い習慣は良い習慣です。次のスクリプトで重要です。
_old="$IFS"
IFS='
'
for i in $(<file)
do
(
IFS="$old"
echo "$i"
)
done
_
データファイルに単語間に複数のスペースが含まれている場合:
_$ cat file
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
_
出力:
_$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
_
二重引用符なし:
_$ cat bq.sh
old="$IFS"
IFS='
'
for i in $(<file)
do
(
IFS="$old"
echo $i
)
done
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
_
IFS
変数を使用して、フィールド区切り文字として改行を指定できます。
IFS=$'\n'
for i in `cat file`
do
echo $i
done
内部フィールド区切り文字(IFS)の変更と結合されたforループは、意図したとおりにファイルを読み取ります
入力用
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
IFS変更と組み合わせたforループ
old_IFS=$IFS
IFS=$'\n'
for i in `cat file`
do
echo $i
done
IFS=$old_IFS
結果は
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
IFS-内部フィールド区切り文字を設定して、必要なものを取得できます。
行全体を一度に読み取るには、IFS = ""を使用します。
cat filename | while read i
do
echo $i
done