しばらく前にファイルから入力を読み取るコードを見つけましたが、Stack Exchangeを介して自分のニーズに合わせて調整できたと思います。
while read -r line || [[ -n "$line" ]]; do
if [[ $line != "" ]]
then
((x++))
echo "$x: $line"
# <then do something with $line>
fi
done < "$1"
今私のスクリプトを見直し、それが何をしているのか理解しようとしています。この文が何をしているのかわかりません。
while read -r line || [[ -n "$line" ]];
私はその-r
オプションが私たちが生のテキストを読んでいることを意味していることを知っていますが、$line
文の対応する部分については混乱しています。|| [[ -n "$line" ]]
誰かがこれが何をしているのかを説明できますか?
答え1
[[ -n "$line" ]]
$line
(読んだばかりの変数)が空でないことをテストしますread
。read
次の場合は成功を返すので便利です。〜しない限りそれを見る改行文字ファイルが終了する前に。入力に末尾に改行文字のない行の断片が含まれている場合、このテストはその行をキャプチャし、ループは最後の不完全な行も処理します。追加のテストがなければ、不完全な行を読み取ることができますが、$line
ループでは無視されます。
POSIXが定義しているので、「不完全な行」と言います。テキストファイルそして一行各行の末尾に改行文字が必要です。他のツールread
も管理できます。wc -l
改行文字の数を計算します。したがって、最後の不完全な行は無視されます。たとえば、参照してください。ファイルの最後に新しい行を追加するのはなぜですか?そしてテキストファイルが改行で終わるのはなぜですか?それはすべてです。
もちろん、このcmd1 || cmd2
構造はCの同等の構造に似ています。最初のコマンドがエラー状態を返すと、2番目のコマンドが実行され、結果は最後に実行されたコマンドの終了ステータスです。
比較する:
$ printf 'foo\nbar' | ( while read line; do
echo "in loop: $line"
done
echo "finally: $line"
)
in loop: foo
finally: bar
そして
$ printf 'foo\nbar' | ( while read line || [[ -n $line ]]; do
echo "in loop: $line"
done
echo "finally: $line"
)
in loop: foo
in loop: bar
finally:
答え2
これは少し混乱しています。なぜそこにありますが、それが何をしているのかを説明するのは簡単です。長さがゼロでない限りtrueを返す||
ORステートメント。ここで混乱しています。成功(0)終了状態があるときは、whileループは引き続き実行されます。行が空であっても、ファイルの終わりに達するまで行を読み続け、ゼロ終了ステータスを返します。ゼロ以外の終了コードが返された場合にのみ実行され、この場合は空です。テストは次の場合にtrueを返すので、[[ -n
"$line"
read
[[ -n "$line" ]]
read
$line
$line
いいえ空の場合、ゼロ以外の出口に戻り、ループから出ますwhile
。私が知る限り、(@ilkkachuが指摘したように、これは末尾の改行文字が欠落している入力の奇数行をキャプチャします。これらのファイルは有効なテキストファイルではありません。有効な行ではありません。)|| [[ -n "$line" ]]
実際に達成されたことは何もありません。
何はい時々動作する場合は、ちょうどしてくださいwhile read -r line && [[ -n "$line" ]]
。 (AND)を使用すると、行を読み取ることができ、行が空でない場合、ステートメント全体がゼロ&&
状態のみを返すことを意味します。最初の空白行でループが停止read
します。while
推測すると、このコードは可能これを行ったことから修正されました。単にテストを削除する代わりに、作者は&&
これを||
。