コマンドおよびシェル拡張宣言

コマンドおよびシェル拡張宣言

私は次のような行動を偶然発見しましたbash

# The following works
$ declare bar=Hello                               # Line 1
$ declare -p bar                                  # Line 2
declare -- bar="Hello"
$ foo=bar                                         # Line 3
$ declare ${foo}=Bye                              # Line 4
$ declare -p bar                                  # Line 5
declare -- bar="Bye"
# The following fails, though
$ declare -a array=( A B C )                      # Line 6
$ declare -p array                                # Line 7
declare -a array=([0]="A" [1]="B" [2]="C")
$ foo=array                                       # Line 8
$ declare -a ${foo}=([0]="A" [1]="XXX" [2]="C")   # Line 9
bash: syntax error near unexpected token `('`
# Quoting the assignment fixes the problem
$ declare -a "${foo}=(A YYY C)"                   # Line 10
$ declare -p array                                # Line 11
declare -a array=([0]="A" [1]="YYY" [2]="C")

シェル拡張のため

  1. サポート拡張
    • チルダ拡張
    • パラメータと変数の拡張
    • 算術拡張
    • プロセスの置き換え
    • コマンドの置き換え
  2. 噴射
  3. ファイル名拡張子

9行がトークンに分割された後(および引用符が削除された後)、コマンド行で最後のコマンドが実行される前に9行が失敗するとは予想されません。

bash9行が承認されないのはなぜですか?または言い換えれば、bash9行を失敗させ、10行を成功させるために処理する方法で私が逃しているのは何ですか?

それにもかかわらず、引用が常に直接的に機能するわけではなく、配列要素が空白などを含む文字列である場合は、特別な注意が必要です。

答え1

長すぎます;dr;私の考えでは、構文上の問題に過ぎず、その背後に何か壮大なデザインがあると仮定してはいけません。

bison / yaccを使用して生成されたBashパーサーしかし、他の多くの言語(C、Perlなど)と同様に、「きれいな」パーサーではありませんが、状態変数の構文と分離/並列parser_state

この状態変数に含まれるフラグはですPST_ASSIGNOK。この値は、WORDトークンで解析される特定の組み込み関数がASSIGNMENT_BUILTINそのフラグにあるときに設定されます。

これらの「割り当て組み込み関数」は、、、localおよびtypesetです。declarealiasexportreadonly

これらの組み込み関数の右側に割り当てて使用すると、パーサーに括弧をPST_ASSIGNOKトークンの一部として処理するように指示します。WORDただし、現在のトークンが実際にトークンであるかどうかを判断するルールは変更されません。仕事${foo}=(...)許可されている割り当てではないため、単一の単語として解析されず、括弧は同様に構文エラーを引き起こしますecho foo(bar)

コマンドラインを解析したら、次のようになります。拡大するそして、拡張の一部としてすべての複合割り当て(WORD表示W_COMPASSIGNvar=(1 2)が実行され、に置き換えられvar、次のような組み込み関数に引数として渡されますdeclare。ただし、declareすべての拡張後にフォームのパラメータを取得すると、フォームは再解析され、拡張var=(...)されます。

したがって、変数がすでに定義されているかどうかによって。または tovarname=foo; declare "$var=(1 2 3)"と同じ場合があります。declare foo='(1 2 3)'declare foo=(1 2 3)

$ declare 'foo=(1 2 3)'; typeset -p foo
declare -- foo="(1 2 3)"
$ declare foo=(1); typeset -p foo
declare -a foo=([0]="1")
$ declare 'foo=(1 2 3)'; typeset -p foo
declare -a foo=([0]="1" [1]="2" [2]="3")

私はこのコーナーケースに頼ることは良い考えではないと思います。

$ declare 'bar=(1 ( )'; typeset -p bar
declare -- bar="(1 ( )"
$ declare bar=(1); typeset -p bar
declare -a bar=([0]="1")
$ declare 'bar=(1 ( )'; typeset -p bar
bash: syntax error near unexpected token `('

関連情報