読み取り-a配列-d '\ n' <foo、終了コード1


8

実行しようとすると

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

回答:


14

説明する必要があるのは、コマンドが終了コードではなく機能しているように見えることです

'\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。これも例外ではありません。ここにカップルがあります:

  1. を指定しない限り-rreadはバックスラッシュのエスケープシーケンスを解釈します。それが実際に必要な場合を除いて(たまにそうですが、たまにしかありません)、-r入力にバックスラッシュがあるまれなケースで文字が消えないように指定することを忘れないでください。

  2. read終了コード1 を返すという事実は、それが失敗したことを意味しません。ラインターミネーターを見つけることを除いて、それは成功したかもしれません。したがって、次のようなループには注意してください。最後の行の最後に改行がないというまれなケースでは、最後の行でwhile read -r LINE; do something with LINE; done 失敗するためdo somethingです。

  3. read -r LINE バックスラッシュは保持されますが、先頭または末尾の空白は保持されません。


ありがとう!私は$ '\ n'アプローチを試したと思いましたが、私はそうではないと思います:/ -rについて知っておくと良い
RasmusWL

2
「最後の行に改行がなかったまれなケース」は、「決して使用しない」ことを勧める説得力のある理由ではないようですwhile read。そうでなければ、素晴らしい答え。
グレンジャックマン2013年

@glennjackman:while readループ内に何もない限り使用できます。そうでなければ、それはあなたを噛むのを待っているバグです-そして私を信じて、私は噛まれました。
リチ2013年

2
最後の行には常に改行があります。これが行の定義方法です。改行で終わります。空でないファイルが改行で終わっていない場合、それはテキストファイルではないため、シェルユーティリティなどのテキスト処理ツールを使用できませんread
Gilles「SO-邪悪なことをやめなさい」

2
@glennjackman:私、主にawkで列化されたファイルを繰り返し処理します。ファイルが大きすぎない行全体を繰り返す場合mapfileは、かなりクールです。簡単で汚いハックのために、私は禁止されたwhileループを使用しますが、それを本番スクリプトに入れるのをやめました。YMMVと私は答えの警告を和らげました。
rici 2013年

4

これが予想される動作です。

ファイルの終わりに遭遇しない限り、戻りコードはゼロです[...]

start cmd:> echo a b c | { read -a testarray; echo $?; }
0

start cmd:> echo -n a b c | { read -a testarray; echo $?; }
1
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.