set-o errexitがこの読み取り/heredoc式を中断するのはなぜですか?

set-o errexitがこの読み取り/heredoc式を中断するのはなぜですか?

私は以下のパターンを使用してbashスクリプトの端末に複数行のメッセージを印刷しました。

read -d '' message <<- EOF
    this is a 
    mulitline
    message
EOF
echo "$message"

これは働いていました。数日前まではモード動作が中断されました。動作を停止するということは、bashがスクリプトでこれらの区切り文字表現を見つけたときに何もしないようで、出力がないことを意味します。
過去数日間に私が考えることができる唯一の変更は、スクリプトが実行される環境が「フル」インストールではなく、Ubuntu 14.04ライブUSBであるということです。その後、スクリプトステートメントの前に
heredocを移動すると、再び機能し始めることがわかりました。set -o errexitつまり、これは機能しません

#!/bin/bash

set -o errexit

read -d '' message <<- EOF
    this is a 
    mulitline
    message
EOF

echo "$message"

結果:(何も)
しかしこれは実際に働く

#!/bin/bash

read -d '' message <<- EOF
    this is a 
    mulitline
    message
EOF

echo "$message"

結果

$ sudo ./script.sh 
this is a 
mulitline
message
  • バッシュ --バージョン-GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu)

答え1

read区切り文字が見つからない場合は、ゼロ以外の終了ステータスが返されます。区切り文字を空の文字列に設定した後、通常はテキストファイルに見つからないNULバイトを区切り文字として使用します。

答え2

EOF(ファイルの終わり)表示に達すると、読み取りコマンドの終了コードは1です。この特別な場合は、-d区切り文字が空のときに常に発生します''。ここで、ソースストリームは\ 0を含めることができない区切り文書です。

$ read -d '' message <<-_ThisMessageEnds_
>     this is a
>     multi line
>     message
> _ThisMessageEnds_
$ exitval=$?
$ echo "The exit val was $exitval"
The exit val was 1.

終了値はエラー(0ではありません)で、AND / OR構文を使用してスクリプトの終了を防ぐことができます。

read -d '' message <<-_ThisMessageEnds_ || echo "$message"
    this is a
    multi line
    message
_ThisMessageEnds_

これによりメッセージがコンソールに送信されますが、コンソールのシャットダウンは防ぎますerrexit

しかし今後は縮小する予定なので、ただ使ってみてはいかがでしょうか?

cat <<-_ThisMessageEnds_
    this is a
    mulitline
    message
_ThisMessageEnds_

読み取りコマンドがより速く実行され、変数が必要なく、終了コードにエラーがなく、維持するコードが少なくなります。

答え3

read -d '' message

最初にエスケープされていない最初のNUL文字(1つを追加しなかったため-r)または入力の最後まで標準入力を読み取り、$IFSバックスラッシュ文字で処理されたデータを区切り文字$messageなしで保存します。

入力にエスケープされていない区切り文字がない場合、終了ステータスはreadゼロではありません。完全終了レコードを読み取ると、0(成功)のみが返されます。

NULで区切られたレコード(出力など)を処理するのに最も便利です(後で構文がfind -print0必要な場合でも)。IFS= read -rd '' record

read正常な戻りを得るには、この文書にNUL区切り文字を含める必要があります。ただしbash、このドキュメントからNUL文字を削除することは不可能です(yashここにドキュメントにNULが含まれているときに無限ループに入るように見える最初のNULまたはksh93以降のすべてのアイテムを削除するよりも少なくとも優れています)。

zshドキュメントに NUL を含めたり、変数に保存したり、組み込み関数/関数に NUL 文字を引数として渡したりできる唯一のシェルです。では、zsh次のことができます。

NUL=$'\0'
IFS= read -d $NUL -r var << EOF
1
2
3$NUL
EOF

( . のような NUL 区切り文字としてもzsh理解されますが、NUL バイトはコマンドラインでサポートされていないため、 like in に空の引数を渡します。)read -d ''bashread -d $'\0'bashreadread -d ''bash

(次に改行があることに注意してください$NUL

bashさまざまな文字を使用できます。

ONE=$'\1'
IFS= read -d "$ONE" -r var << EOF
1
2
3$ONE
EOF

しかし、次のようにすることもできます。

var=$(cat <<EOF
message
here
EOF
)

それでもNUL文字は使用できません。ただし、これは標準コードなので、zsh / bash固有のコードに頼る必要はありませんread -d。また、すべての末尾の改行を削除するため、組み込みksh93機能が有効になっていないcat場合は追加のプロセスとコマンドが生成されます。

答え4

使用set -o errexitしてスクリプトが中断されると、何かが間違っていることを意味します。

ここはread, 入力内容を正しく読み取れません。

bash使用するread -d ''ときread組み込み\0ヌル文字は行終端として使用されます。したがって、\0入力に何もない場合は、readすべての入力が変数として読み取られ、messageゼロ以外の終了ステータスが返され、エラーを示します。

$ while read -d '' line; do echo "$line"; done < <(printf '1')

次の場合は何も印刷しません。

$ while read -d '' line; do echo "$line"; done < <(printf '1\0')
1

あなたのための1

readまた、EOFに達するとゼロ以外の状態を返しますが、これはループreadと一緒に使用するとwhile読み取る入力がなくなり、whileループが終了する可能性があることを示すために使用されます。これはあなたの質問とは関係ありません。

関連情報