Bash: $() コマンド置換で二重引用符をエスケープする

Bash: $() コマンド置換で二重引用符をエスケープする

一部のパラメータが変数から来た場合、コマンド置換がどのように機能するかを理解できません。

これを説明するために一連のコマンドを提供します。

まずA B C、tmpディレクトリ内にディレクトリを作成し、新しいディレクトリに新しいファイルを作成しますabcfile

user@desktop /tmp
$ pwd
/tmp

user@desktop /tmp
$ mkdir "A B C"

user@desktop /tmp
$ ls
'A B C'

user@desktop /tmp
$ touch "A B C"/abcfile

user@desktop /tmp
$ ls "A B C"/
abcfile

A B C変数に新しい値を代入し、ディレクトリの内容を一覧表示するコマンドを呼び出すさまざまな方法を$DIR試してみましょう。ls

user@desktop /tmp
$ DIR="A B C"

変数が引用されない場合、コマンドは期待どおりに失敗します。

user@desktop /tmp
$ ls $DIR
ls: cannot access 'A': No such file or directory
ls: cannot access 'B': No such file or directory
ls: cannot access 'C': No such file or directory

変数を参照した後、期待どおりに動作します。

user@desktop /tmp
$ ls "$DIR"
abcfile

コマンドの出力を文字列にしたい場合

user@desktop /tmp
$ echo $(ls "$DIR")
abcfile

このコマンドは動作しますが、なぜ動作しますか? Shellcheckによると、これは実際には正しくありません。変数は二重引用符の外になければなりません。

user@desktop /tmp
$ echo "$(ls "$DIR")"
abcfile

内部変数に二重引用符がないと、コマンドは失敗します。

user@desktop /tmp
$ echo "$(ls $DIR)"
ls: cannot access 'A': No such file or directory
ls: cannot access 'B': No such file or directory
ls: cannot access 'C': No such file or directory

ベストアンサー1

私は出力コマンドの出力をecho "$(somecommand)"asに置き換える必要はなく、この構成を単に例として使用していることを知っているとします。somecommandecho

出力が印刷されるため、コマンドはecho $(ls "$DIR")「動作」します。ls "$DIR"abcfileecho

この場合、ここでコマンドの置き換えを引用しても効果はありません。ファイル名の文字を含むように文字列を変更しない限り、文字列にはabcfile引用符は必要ありません(下記の理由を参照)。$IFS

ただし、次の点を考慮してください。

A B C/
|-- A*
`-- abcfile

今:

$ echo "$(ls "$DIR")"
A*
abcfile
$ echo $(ls "$DIR")
A B C abcfile

最後の出力では、ファイル名をA*ディレクトリ名と一致するファイル名ワイルドカードパターンに拡張しますA B C。また、出力で改行文字が失われたことがわかりますls

シェルが失われるため、改行文字が失われます。噴射引用符のない出力では、lsスペース、タブ、および改行(のデフォルト$IFS)を使用して単語に分割します。

ディレクトリ名には、A B C単語分割によって生成された単語が含まれているため挿入されます。ファイル名の生成(ワイルドカード)。

新しいファイル名がある場合は、A* A*ディレクトリ名が2回挿入されます。

A B C/
|-- A* A*
`-- abcfile
$ echo $(ls "$DIR")
A B C A B C abcfile

関連:

おすすめ記事