`$var && action` を使用して、空の変数を論理「true」として扱います(シェル解析)。

`$var && action` を使用して、空の変数を論理「true」として扱います(シェル解析)。

特定のコマンドラインフラグを$debug次に設定するtrueか、次のものに基づいてできる単純なデバッグスタイルを検討してください。false

$debug && echo "Something strange just happened" >&2

${debug:-false}すべての機能を備えた-type関数など、値の設定を防ぐためのより良い方法があることを知っていますが、logMessage()今はこれを控えておきます。

$debugまだ設定されていないか空の悪い場合を想定してください。私は$debug && echo …そのようなnull値が$debug解析され、と評価され、&& echo …後続の構文エラーが発生すると予想しました。しかし、むしろそのような評価を受けて: && echo …最終的には実行されるようだecho

bashとしてkshテストしましたが、dashシナリオは一貫して維持されました。

私の理解は、これらの2行が等しいと解析されていますが、明らかにそうではありません。

unset debug; $debug && echo stuff
unset debug; && echo stuff

このようなエラーが原因で失敗せず、設定されていない変数が論理的に真であるかのようにコードが動作するのはなぜですかsyntax error near unexpected token `&&'

答え1

ただし、拡張が完了した後は構文を確認しません。

$foo拡張後に生成されたフィールドの数と変数の値に関係なく、構文的に有効な単純なコマンド。拡張前のシェル「単語」で十分です。

シェルが他の構文(キーワード、引用符など)も解析することを期待する拡張結果$foo && whateverと同じです。&& whateverまだ完了していません。

したがって:

foo="then if"
$foo

構文エラーではありませんが、次の一般的なコマンドを実行してみてくださいthen (コマンドが存在しない可能性があり、エラーが発生しましたが、できる存在し、「コマンドが見つかりません」というエラーは次のとおりです。その他then if1つは、単独で実行しようとしたときに発生する構文エラーです。 )。

そして:

foo=
$foo

構文エラーではありませんが、実行しようとしていますが…まあ、特別なケースである「コマンド名」がないからではなく、エラーではありません。バラより2.9.1 簡単なコマンド:

与えられた単純なコマンドを実行する必要がある場合は、コマンドテキストの最初から最後まで、次の拡張、割り当て、およびリダイレクトが行われます。

  1. [配布、リダイレクト]

  2. 変数の割り当てやリダイレクト以外の単語は拡張する必要があります。もし拡張後もすべてのフィールドは残ります。最初のフィールドはコマンド名として扱われる必要があり、残りのフィールドはコマンドの引数です。 [...]

「if」に注意してください。

コマンド名が存在しない場合、変数の割り当ては現在の実行環境に影響し、コマンド置換がない場合は終了状態は 0 です。

したがって、$foo空または設定されていない場合:

$foo

何もせずに終了状態を0に設定します。

bar=asdf $foo

終了状態を0$barに設定し、0に設定します。asdfと同じですbar=asdfが、$foodidがコマンド名に拡張されている場合、割り当てはそのコマンドにのみ適用されます。

答え2

シェルコマンド言語仕様セクションで2.9.1 簡単なコマンド、すべてのリダイレクト、グローバル/パラメータ拡張などを実行した後:

コマンド名がある場合は、次の説明に従って実行を続行する必要があります。命令の検索と実行。コマンド名はありませんが、コマンドにコマンド置換が含まれている場合、コマンドは最後に実行されたコマンド置換の終了状態で完了する必要があります。それ以外の場合、コマンドはゼロ終了状態で完了する必要があります。

あなたは「そうでない場合」カテゴリに属します。

答え3

単純なコマンドは、割り当て、リダイレクト、および引数で構成されます(最初の引数は、実行するコマンドを派生させるために使用されます)。

すべてオプションです。引数がないと、すべてのリダイレクトが実行され、リダイレクトと割り当て先で最後の実行コマンドの置き換え(または空の引数リストを生成するために使用されたコマンド)が成功する限り、コマンドは成功します。ただし、IIRCではどのようなリダイレクトと割り当ても指定されていません。まず仕上げてください。

これらすべてがうまくいきました。

  • a=whatever:コマンドなし、リダイレクトなし、割り当てのみあり
  • $(true):コマンドなし、リダイレクトなし、割り当てなし、正常なコマンド置換結果は空のリストになります。
  • a=$(false) b=$(true).割り当てのみ、最後のコマンドが正常に置き換えられます。
  • > /dev/null:コマンドなし、リダイレクト成功
  • > "$(echo /dev/null)": コマンドなし、コマンド置換、リダイレクトが成功
  • empty=; a=foo $empty > /dev/null:割り当てとリダイレクト、空のリストが発生したため、引数/コマンドのない拡張。
  • empty=; $empty:上記と同じで、割り当てやリダイレクトはありません。

以下は失敗します。

  • false
  • a=$(false)
  • $(false)
  • > /etc/passwd/foo
  • < /dev/null"$(false)"
  • ...

指定されていません:

  • $(true) > /dev/null$(false)
  • a=$(false) > /dev/null$(true)

答え4

2つのコマンド&&パイプラインリストを結合する演算子を考えてください(3.2.4 命令リスト)。

最初のコマンドはです$debug。変数が設定されていない場合、コマンドはありません。プロンプトでEnterキーを押すのと同じように、コマンドは実行されませんが、ゼロ以外の終了状態もありません。

の左側にはエラーがないので、&&右側は自由に実行されます。

引用すると、目的のエラーが発生します。

  • 強く打つ

    $ unset debug; $debug && echo hmm
    hmm
    $ unset debug; "$debug" && echo hmm
    bash: : command not found
    
  • ケシ

    $ unset debug; $debug && echo hmm
    hmm
    $ unset debug; "$debug" && echo hmm
    ksh: : cannot execute [Is a directory]
    
  • スプリント

    $ unset debug; $debug && echo hmm
    hmm
    $ unset debug; "$debug" && echo hmm
    dash: 9: : Permission denied
    

関連情報