while read ループは、stdin から読み取っていないにもかかわらず、最初の行の後に停止します

while read ループは、stdin から読み取っていないにもかかわらず、最初の行の後に停止します

というファイルがありtestます

test
test

そして私はこのコマンドを実行しています

while read line
do
echo "$line"
done </tmp/test

これは「test」を 2 回出力する必要がありますが、1 回しか出力されません。 を使用してもwhile IFS= read -r line何も変わりません。これを修正するには、3 番目の空行を出力する必要がありますが、それでも動作するはずです。

答え1

試す:

while IFS='' read -r line || [ "$line" ]

はい、標準入力 (stdin) から読み取っており、<testリダイレクトは stdin に行われます。

おそらく、read はテキスト ファイルで動作するように設計されているのでしょう。正しいテキストファイルは改行で終わる必要があります

作ります改行でファイルを終了すると非常に高速になることが判明:

[ -n "$(tail -c1 file)" ] && printf '\n' >>file 

しかし、ファイルを編集して改行を追加できない場合(行が欠落している場合)、解決策としては、何かが読み取られたかどうかを(さらに)テストすることです。

while read line || [ "$line" ]

これにより、読み取りが失敗した場合 (デフォルトでは改行を読み取らずにファイルの最後まで到達した場合) に、何かが読み込まれた場合 (in "$line") にループが実行されます。

これは、改行で終わるファイルでも、そうでないファイルでも正しく機能します。

いいえ、aはIFS='' read最終行の読み取りに(直接)影響しません。実際、IFS=''(デフォルトのIFSと比較して)[あ]スペース、タブ、改行などの文字は、分割にのみ影響します。いくつかの変数(先頭および/または末尾の空白の削除に影響するほか(IFSに空白のみが含まれている場合)[b]))。変数が 1 つ ( ) しかないため、"$line"分割は実行されません。

読み取りオプション-d(bash 2.04 以降) も役に立ちません。一致する特定の「ファイル終了」文字はありません (最後のバイトは任意の文字になります)。

残された選択肢は次のいずれかです。

  • ファイルを修復して正しいテキストファイルにする
  • 変数に何かが読み込まれたかどうかをテストしますline

正しいスクリプトは次のようになります。

#!/bin/bash
while IFS='' read -r line || [ "$line" ]
do
    printf '%s\n' "$line"
done <test

IFS='' は、IFS の一般的でない値による問題を回避するために使用されます。


[a][b]もちろん、IFS に何らかの値がある場合、他の多くの文字が削除される可能性があります。('x' で終わる値の場合) を試してください。

printf "test\ntesx\ntest" | while IFS="x" read -r line || [ "$line" ]; do echo "$line"; done

いいえ、zsh は別のことを行います。

関連情報