私は、文字列を引用することは、文字列を解析するシェルを避けるために常に良い習慣であると確信していました。
それから私はこれを見つけました:
$ x='('
$ [ "$x" = '1' -a "$y" = '1' ]
bash: [: `)' expected, found 1
問題を切り離そうとしましたが、同じエラーが発生しました。
$ [ '(' = '1' -a '1' = '1' ]
bash: [: `)' expected, found 1
私は次のように問題を解決しました。
[ "$x" = '1' ] && [ "$y" = '1' ]
私はまだここで何が起こっているかを知る必要があります。
答え1
[
これは非常にあいまいなケースであり、テスト組み込みの定義方法にバグがあると思うかもしれませんが、これは多くの[
システムで使用できる実際のバイナリの動作と一致します。私が知っている限り、、、、などの[
演算子と一致する値を持つ特定のケースと変数にのみ影響します。(
!
=
-e
Bash と POSIX シェルでこの問題を解決する理由と回避策について説明します。
説明する:
以下を考慮してください。
x="("
[ "$x" = "(" ] && echo yes || echo no
問題ありません。上記のコードはエラーや出力を生成しませんyes
。これが私たちが期待する仕組みです。必要に応じて、比較文字列をおよび'1'
値に変更でき、x
期待どおりに機能します。
実際の/usr/bin/[
バイナリも同じように動作します。たとえば、実行すると、'/usr/bin/[' '(' = '(' ']'
プログラムは引数が単一の文字列比較操作で構成されていることを検出できるため、エラーは発生しません。
いつ私たちがそして2番目の表現を使用してください。有効な限り、2番目の表現が何であるかは重要ではありません。例えば、
[ '1' = '1' ] && echo yes || echo no
outputyes
は明らかに有効な表現ですが、2つを組み合わせると
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
x
Bash は is または の場合にのみ(
式を拒否します!
。
実際のプログラムを使用して上記の内容を実行すると[
、
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
エラーは理解できます。シェルが変数置換を実行するため、/usr/bin/[
バイナリは引数(
=
(
-a
1
=
1
と終端子のみを受け取るため、開かれている]
括弧がサブ式を開始するかどうかは当然解析できません。そして 操作が含まれます。もちろん、これを2つの文字列比較で解析することは可能ですが、これを行うと、括弧で囲まれたサブ式が正しい式に適用されると問題が発生する可能性があります。
実際に問題は、シェル組み込みが式を確認する前に値を拡張したかの[
ように動作するということです。x
(これらのあいまいさと変数の拡張に関するその他の点は、[[ ... ]]
Bashがテスト式を実装し、テスト式を使用することを推奨する重要な理由です。)
回避策は簡単で、sh
古いシェルを使用しているスクリプトによく表示されます。一般x
に、式が文字列比較として認識されるように、文字列(比較される2つの値)の前に「安全な」文字を追加します。
[ "x$x" = "x(" -a "x$y" = "x1" ]
答え2
[
別名test
参照:
argc: 1 2 3 4 5 6 7 8
argv: ( = 1 -a 1 = 1 ]
test
括弧内のサブ式を受け入れるので、左括弧はサブ式を開き、それを解析しようとします。パーサーはこれを=
サブ式の最初のものと見なし、それを暗黙的な文字列長テストと見なします。したがって、サブ式に従う必要があります。パーサーが1
代わりに探して閉じ括弧で)
。
正確に3つの引数があり、中央の引数がtest
認識された演算子の1つである場合は、括弧内のサブ式を見つけることなく、最初と3番目の引数に対応する演算子を適用します。
詳細については、を確認してman bash
検索してくださいtest expr
。
結論:使用される解析アルゴリズムはtest
比較的複雑です。ただ簡単な表現を使ってシェル演算子を使用!
して&&
結合します||
。