他のコマンドを介して間接的に渡された配列を正しく参照する方法

他のコマンドを介して間接的に渡された配列を正しく参照する方法

ファイル名の配列をコマンドに渡し、正しい参照を維持する必要があります。今まではそんなに良くなった。残念ながら、このコマンドは実際には他のコマンドによって呼び出されるサブコマンドです。具体的には、コマンドは次のようになります。

git filter-branch --index-filter \
    'git rm -rf --cached ‹file1› ‹file2›…' \
    HEAD

簡単にするために、以下は同じ問題を示すより簡単なコマンドに置き換えます。

printf '%s\n' 'cmd file1 file2…'

これで配列ができましたfiles=('a b' c)。私が望む結果は、上記のコマンドが印刷されることです連続して、必要に応じて、次の各トークンを個別に引用しますcmd(たとえば、空白がある場合)。

ファイル名を手動で拡張して引用すると機能します。

$ printf '%s\n' 'cmd '\''a b'\'' c'
→ cmd 'a b' c

(または一重引用符と二重引用符を混合して同じ結果を得ることもできます。)

しかし、配列を渡そうとするともう機能しません。

  1. $ (set -x; printf '%s\n' "cmd '${files[@]}'")
    + printf '%s\n' 'cmd '\''a b' 'c'\'''
    → cmd 'a b
    c'
    
  2. $ (set -x; printf '%s\n' 'cmd '\'"${files[@]}"\')
    + printf '%s\n' 'cmd '\''a b' 'c'\'''
    → cmd 'a b
    c'
    
  3. $ (set -x; printf '%s\n' 'cmd '"${files[@]}")
    + printf '%s\n' 'cmd a b' c
    → cmd a b
    c
    

私は(3)が動作しないという事実には驚きません(完全さのために含まれています)。出力によると、set -xシェルは(1)と(2)の個々の配列要素を正しく引用し、内容全体の周りにエスケープされた引用符を追加します。ただし、個別に参照された項目を分類します。これを防ぐ方法はありますか?


しかし、Shellcheck(SC2145)は、上記のセクションを上記のセクション[@]に置き換えることを提案します。[*]これは明らかに空白のあるファイル名を壊します。

ベストアンサー1

  1. 配列の代わりに引数のset -- file1 file2 ...リストを次に埋めます。bash パラメータ変換そしてQウテオペレーター:

    set -- 'a "b' c "d 'e" "f 'g "'"h' ; (set -x; printf 'cmd %s\n' "${*@Q}")
    

    出力:

    + printf 'cmd %s\n' ''\''a "b'\'' '\''c'\'' '\''d '\''\'\'''\''e'\'' '\''f '\''\'\'''\''g "h'\'''
    cmd 'a "b' 'c' 'd '\''e' 'f '\''g "h'
    

    または、その部分を削除すると、set -x; 出力は次のようになります。

    cmd 'a "b' 'c' 'd '\''e' 'f '\''g "h'
    
  2. さんのコメントLL3以下を要求しないより良いアプローチを提案してください set -- ...

    export x; n=(a "b 'c"); x="${n[@]@Q}"
    ( n=($x); printf 'cmd %s\n' "${n[*]}"; )
    

    簡単なバージョン:

    n=(a "b 'c"); echo "cmd ${n[@]@Q}"
    

    出力:

    cmd 'a' 'b '\''c'
    
  3. 別の方法はbash パラメータ変換そしてA移動する演算子(必須eval):

    export x;n=(a b 'c d');x="${n[@]@A}"; (eval "$x";printf '%s\n' "${n[@]}")
    

    出力にはprintf表示される内容が表示されます。

    a
    b
    c d
    

おすすめ記事