私が実行しようとすると
read -a fooArr -d '\n' < bar
終了コードは 1 です。もし私が望むことをしても、各行をbar
配列の要素に入れますfooArr
(bash 4.2.37を使用)。
なぜこれが起こるのかを説明できる人はいますか?
以下のようにこの問題を解決するための別の方法を見つけたので、これは私が要求するものではありません。
for ((i=1;; i++)); do
read "fooArr$i" || break;
done < bar
または
mapfile -t fooArr < bar
答え1
説明する必要があるのは、終了コードではなく、コマンドが機能しているようです。
'\n'
バックスラッシュ\と文字という2つの文字ですn。あなたが必要だと思うのは、$'\n'
それが改行文字であるということです(しかしそれも正確ではありません。以下を参照してください)。
この-d
オプションは次のことを行います。
-d delim continue until the first character of DELIM is read, rather than newline
したがって、オプションがない場合は、read
改行文字を読み、$IFS
文字を区切り文字として行を単語に分割し、その単語を配列に配置します。を指定した場合、-d $'\n'
行区切り文字を改行に設定すると、次のことができます。同じこと。設定とは、-d '\n'
最初の文字である最初のバックスラッシュ(ただし、再び以下を参照)まで読むことを意味しますdelim
。ファイルにバックスラッシュがないため、read
ファイルの最後で終了します。
Exit Status:
The return code is zero, unless end-of-file is encountered, read times out,
or an invalid file descriptor is supplied as the argument to -u.
これが終了コードが1の理由です。
コマンドが機能すると考えると、ファイルにスペースがないと結論付けることができます。したがって、バックスラッシュを見つけるための無駄な希望でファイル全体を読み取った後は、改行を含むスペース(デフォルト)read
で区切られます。$IFS
。したがって、各行(または行に複数の単語が含まれている場合は各単語)が配列に格納されます。
バックスラッシュ盗難事件
これで、ファイルにバックスラッシュが含まれていないことをどうやって知ることができますか?-r
次の宛先にフラグを指定していないためですread
。
-r do not allow backslashes to escape any characters
したがって、ファイルにバックスラッシュがある場合は、2つが連続していない限り削除されます。もちろん、read
終了コードが1であるという証拠があり、これはバックスラッシュが見つからなかったことを意味するので、連続した2つがなかったことを意味します。
主なポイント
Bashは、例外なくほとんどすべてのコマンドの後ろに隠されたトラップがなければ、Bashではありませんread
。以下はいくつかあります。
バックスラッシュエスケープシーケンスは、指定しないと
-r
解釈read
されます。これが実際に望むものではない場合(たまにそうなることもありますが、時々だけ)、-r
入力にバックスラッシュがあるまれな場合に文字が消えないように指定することを覚えておく必要があります。終了コード1を返しても
read
失敗したという意味ではありません。行終端者を見つけること以外は成功した可能性が高いです。したがって、次のループに注意してください。まれに、最後の行の末尾に改行文字がないため、while read -r LINE; do something with LINE; done
最後の行を処理できません。do something
read -r LINE
バックスラッシュは保持されますが、先行または末尾のスペースは保持されません。
答え2
これは予想される動作です。
ファイルの終わりが見つからない限り、戻りコードは0です。 [...]
start cmd:> echo a b c | { read -a testarray; echo $?; }
0
start cmd:> echo -n a b c | { read -a testarray; echo $?; }
1