回答:
set -e
サブコマンドまたはパイプラインがゼロ以外のステータスを返す場合、シェルを終了します。
インタビュアーがおそらく探していた答えは次のとおりです。
init.dスクリプトを作成するときに「set -e」を使用するのは危険です。
http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 から-
init.dスクリプトでset -eを使用する場合は注意してください。正しいinit.dスクリプトを作成するには、デーモンが既に実行されているか、init.dスクリプトを中止せずに既に停止している場合、さまざまなエラー終了ステータスを受け入れる必要があります。init.dスクリプトの場合、多くの場合、set -eを使用せず、代わりに各コマンドの結果を個別に確認する方が簡単です。
これは、インタビュアーの観点からの有効な質問です。なぜなら、サーバーレベルのスクリプティングと自動化に関する実用的な知識を候補者が評価するからです。
からbash(1)
:
-e Exit immediately if a pipeline (which may consist of a
single simple command), a subshell command enclosed in
parentheses, or one of the commands executed as part of
a command list enclosed by braces (see SHELL GRAMMAR
above) exits with a non-zero status. The shell does not
exit if the command that fails is part of the command
list immediately following a while or until keyword,
part of the test following the if or elif reserved
words, part of any command executed in a && or ││ list
except the command following the final && or ││, any
command in a pipeline but the last, or if the command’s
return value is being inverted with !. A trap on ERR,
if set, is executed before the shell exits. This option
applies to the shell environment and each subshell envi-
ronment separately (see COMMAND EXECUTION ENVIRONMENT
above), and may cause subshells to exit before executing
all the commands in the subshell.
残念ながら、「スクリプトの残りの部分は実行されない」または「おそらく実際の問題をマスクする可能性がある」以外は、なぜ危険なのかを考えるほど創造的ではありません。
set
ます!私はいつもで終わるbuiltin(1)
。ありがとう。
set
にbefoundすることですman 1 bash
?そして、巨大なマニュアルページでキーワードの-e
オプションをどのように見つけることができますset
か?/-e
ここで検索することはできません
help set
set -e
スクリプトのさまざまなセクションでオンとオフを切り替えることができることに注意してください。スクリプト全体の実行中にオンにする必要はありません。条件付きで有効にすることもできます。とはいえ、自分でエラー処理を行っている(または行っていない)ため、私は使用しません。
some code
set -e # same as set -o errexit
more code # exit on non-zero status
set +e # same as set +o errexit
more code # no exit on non-zero status
また、注目に値するのは、特定の状況でtrap
どのようにset -e
機能するかを説明するコマンドのBashのマニュアルページセクションです。
失敗したコマンドがwhileキーワードまたはuntilキーワードの直後のコマンドリストの一部、ifステートメントのテストの一部、&&または⎪⎪リストで実行されたコマンドの一部、またはコマンドの場合、ERRトラップは実行されません戻り値は!によって反転されています。これらは、errexitオプションが従うのと同じ条件です。
そのため、ゼロ以外のステータスが終了を引き起こさない条件がいくつかあります。
危険なのは、いつset -e
出てくるのか、いつ出ないのかを理解せず、何らかの無効な仮定の下で誤ってそれに頼ることにあると思います。
BashFAQ / 105も参照してください。なぜ-eを設定(または-o errexitを設定、またはERRをトラップ)しても期待どおりの結果が得られないのはなぜですか?
これは就職の面接のためのクイズであることに留意してください。質問は現在のスタッフによって書かれたものであり、間違っている可能性があります。これは必ずしも悪いことではなく、誰もが間違いを犯し、インタビューの質問は多くの場合、レビューなしで暗い隅に座り、インタビュー中にのみ出てきます。
「set -e」が「危険」とみなすものを何もしないことは完全に可能です。しかし、その質問の著者は、「set -e」が彼ら自身の無知または偏見のために危険であると誤って信じるかもしれません。たぶん彼らはバグのあるシェルスクリプトを書き、それが恐ろしく爆撃し、実際には適切なエラーチェックを書くことを怠っていたのに、「set -e」が原因だと誤って考えていました。
私は過去2年間でおそらく40件の就職面接に参加しており、面接官は時々間違った質問をしたり、間違った答えを持っています。
または、それは不完全な質問ですが、完全に予想外ではありません。
または、これは良い説明かもしれません:http : //www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html
set -e
スクリプトでbashに、ゼロ以外の戻り値が返されたときに終了するように指示します。
何かに対するアクセス許可を開いていない限り、それがどのように迷惑で、バグがあり、危険かはわかりません。また、再び制限する前に、スクリプトは死にました。
set -e
実際、スクリプトのエラーチェックを無視するのは怠lazだと言われています。多くの場合、それらのスクリプトはどのように見えますか。必然的に維持する必要があります
set -e
特定の条件下を除き、ゼロ以外の終了コードが検出された場合、スクリプトを終了します。いくつかの言葉でその使用の危険性を要約すると:それは人々がそれを考えるように振る舞わない。
私の意見では、互換性のためだけに存在し続ける危険なハックと見なされるべきです。このset -e
ステートメントは、エラーコードを使用する言語のシェルを、例外のような制御フローを使用する言語に変換するものではなく、単にその動作をエミュレートしようとするものです。
グレッグウーレッジは、次の危険性について多くのことを述べていset -e
ます。
set -e
)2番目のリンクには、の直感的で予測できない動作のさまざまな例がありset -e
ます。
の直感に反する動作の例set -e
(上記のWikiリンクから取得したもの):
セット-e x = 0 x ++ echo "xは$ xです"上記により、シェルスクリプトは早まって終了し
let x++
ます。これは、0を返すためです。これは、let
キーワードによって偽の値として扱われ、ゼロ以外の終了コードになります。set -e
これに気付き、サイレントでスクリプトを終了します。セット-e [-d / opt / foo] && echo "警告:fooは既にインストールされています。上書きします。" >&2 echo "fooをインストールしています..."
上記は期待どおりに動作し、/opt/foo
既に存在する場合は警告を出力します。
セット-e check_previous_install(){ [-d / opt / foo] && echo "警告:fooは既にインストールされています。上書きします。" >&2 } check_previous_install echo "fooをインストールしています..."
上記は、1行が関数にリファクタリングされているという唯一の違いにもかかわらず、/opt/foo
存在しない場合は終了します。これは、元々set -e
動作していたという事実がの動作に対する特別な例外だからです。a && b
ゼロ以外を返す場合、無視されset -e
ます。ただし、関数であるため、関数の終了コードはそのコマンドの終了コードと等しくなり、ゼロ以外を返す関数はスクリプトをサイレント終了します。
セット-e IFS = $ '\ n'読み取り-d '' -r -a config_vars <config
上記はconfig_vars
ファイルから配列を読み込みますconfig
。作成者が意図しているように、config
行方不明の場合はエラーで終了します。著者は意図しないかもしれないのでconfig
、改行で終わらないなら黙って終了します。set -e
ここで使用されなかった場合config_vars
、改行で終了したかどうかに関係なく、ファイルのすべての行が含まれます。
Sublime Text(および改行を誤って処理する他のテキストエディター)のユーザーは注意してください。
セット-e should_audit_user(){ ローカルグループgroups = "$(groups" $ 1 ")" $ groupsのグループ。行う if ["$ group" = audit]; その後、0を返します。fi やった 1を返す } should_audit_user "$ user"; それから ロガー「ブラー」 fi
ここでの作成者$user
は、何らかの理由でユーザーが存在しない場合、groups
コマンドが失敗し、ユーザーに監査されていないタスクを実行させる代わりにスクリプトが終了することを合理的に期待するかもしれません。ただし、この場合、set -e
終了は有効になりません。$user
何らかの理由で見つからない場合、スクリプトは終了せずに、should_audit_user
関数set -e
は無効であるかのように誤ったデータを返すだけです。
これは、if
ステートメントの条件部分から呼び出された関数に適用されます。ネストの深さに関係なく、定義されている場所に関係なく、set -e
再度その内部で実行しても。if
いつでも使用set -e
すると、条件ブロックが完全に実行されるまでの効果が完全に無効になります。作者がこの落とし穴に気付いていない場合、または関数が呼び出される可能性のあるすべての状況で呼び出しスタック全体を知らない場合、バグのあるコードを記述し、提供さset -e
れる誤ったセキュリティ感覚を少なくとも部分的に非難。
作成者がこの落とし穴を完全に認識している場合でも、回避策は、なしset -e
で書くのと同じ方法でコードを書くことです。作者は、あたかも有効になってset -e
いないかのように手動でエラー処理コードを書かなければならないだけでなく、set -e
それらが存在することで、それらを欺く必要がないと思わせるかもしれません。
のさらなる欠点set -e
:
let x++
上記のような例では、そうではありません。スクリプトが予期せず終了した場合、通常はサイレントに実行され、デバッグが妨げられます。スクリプトが死なず、予想していた場合(前の箇条書きを参照)、より微妙で陰湿なバグが手元にあります。if
-condition箇条書きを参照してください。set -e
、これらのバージョン間で動作が異なるスクリプトを誤って作成する可能性があります。set -e
論争の多い問題であり、周囲の問題に気づいている人がそれに対して推奨している人もいれば、落とし穴を知るのが活発な間は注意を払うだけの人もいます。set -e
すべてのスクリプトでエラー状態のキャッチオールとしてお勧めするシェルスクリプトの初心者は多くいますが、実際にはそのようには動作しません。
set -e
教育に代わるものではありません。
もうスクリプトの流れを制御できないので、危険だと思います。スクリプトが呼び出すコマンドのいずれかがゼロ以外を返す限り、スクリプトは終了できます。したがって、必要なことは、コンポーネントの動作または出力を変更するものを実行するだけで、メインスクリプトを終了することができます。それはもっとスタイルの問題かもしれませんが、間違いなく結果をもたらします。あなたのメインスクリプトが何らかのフラグを設定することになっていて、それが早期に終了したためにそうしなかったらどうしますか?フラグが存在すると想定した場合、または予期しないデフォルト値または古い値で作業しているとシステムの残りの部分に障害が発生することになります。