$()のコマンドによって出力された{1,2}が補間されないのはなぜですか?


8

2つのテキストファイルがあるディレクトリにいます。

$ touch test1.txt
$ touch test2.txt

いくつかのパターンを使用して(Bashで)ファイルを一覧表示しようとすると、機能します。

$ ls test?.txt
test1.txt  test2.txt
$ ls test{1,2}.txt
test1.txt  test2.txt

ただし、パターンがで囲まれたコマンドによって生成される場合、パターンの$()1つだけが機能します。

$ ls $(echo 'test?.txt')
test1.txt  test2.txt
$ ls $(echo 'test{1,2}.txt')
ls: cannot access test{1,2}.txt: No such file or directory

何が起きてる?なぜパターン{1,2}が機能しないのですか?


4
ブレースの展開は一重引用符または二重引用符内では実行されません
セルギーコロディアズニー

3
質問のポイント@SergiyKolodyazhnyyということです?されて引用された、と後に拡張されます$(...)、それを代入するが、ブレース展開はしていません。
Michael Homer

1
@muruいいえ、それは同じ問題ではありません。ここで、展開の順序は重要ではありません。重要なのは、どのコンテキストでどの展開が行われるかです。この質問が重複していても驚くことはありませんが、見つかりませんでした。
Gilles「SO-邪悪なことをやめなさい」19/06/06

1
@mosvy Kshとbashは同じ順序で展開を行いますが、kashはbashがまったく展開しない場合に中括弧展開を行います。Zsh-with-globsubstはbashと同じ拡張を行いますが、順序が異なります。
Gilles 'SO-悪をやめる' 19/06/20

1
@ギレスいいえ、そうではありません。文書化されて簡単に示されているように、ksh(およびzsh)は、グロビングの直前にブレース展開を実行します。zsh-with-globsubstは、$-expansions:の結果に対してブレース展開をまったく実行しませんzsh -o globsubst -c 'a=/e*; b={/b*,/v*}; echo $a; echo $b'
モスビー

回答:


17

それは2つのことの組み合わせです。まず、中括弧の展開はファイル名と一致するパターンではありません。それは純粋にテキストによる置換です。「a [bc] d`(大括弧)と `a {b、c} d`(中括弧)の違い何ですか?を参照してください。次に、二重引用符(ls $(…))の外側でコマンド置換の結果を使用すると、完全な再解析ではなく、パターンマッチング(および単語分割:「split + glob」演算子)のみが発生します。

を使用するls $(echo 'test?.txt')と、コマンドecho 'test?.txt'は文字列を出力しますtest?.txt(最後の改行付き)。コマンド置換の結果は文字列になりますtest?.txt(コマンド置換は後続の改行を削除するため、最後の改行なし)。この引用符で囲まれていない置換は単語分割され、test?.txt空白文字(正確には内の文字$IFS)がないため、単一の文字列で構成されるリストが生成されます。次に、この1要素リストの各要素は条件付きのワイルドカード拡張を受けます?。文字列にワイルドカード文字があるため、ワイルドカード拡張が行われます。パターンtest?.txtは少なくとも1つのファイル名に一致するため、リスト要素test?.txtはパターンに一致するファイル名のリストに置き換えられ、次を含む2要素のリストが生成されますtest1.txttest2.txt。最後にls、2つの引数test1とで呼び出されますtest2

を使用するls $(echo 'test{1,2}')と、コマンドecho 'test{1,2}'は文字列を出力しますtest{1,2}(最後の改行付き)。コマンド置換の結果、文字列になりますtest{1,2}。この引用符で囲まれていない置換は単語分割され、単一の文字列で構成されるリストが生成されますtest{1,2}。次に、この1要素リストの各要素は条件付きワイルドカード展開を受けます。文字列にワイルドカード文字がないため、何も行われません(要素はそのままです)。したがってls、単一の引数で呼び出されますtest{1,2}

比較のために、これはで何が起こるかls $(echo test{1,2})です。コマンドecho test{1,2}は文字列を出力しますtest1 test2(最後の改行付き)。コマンド置換の結果、文字列になりますtest1 test2(最後の改行なし)。この引用符で囲まれていない置換は単語分割され、2つの文字列test1とが生成されますtest2。次に、どちらの文字列にもワイルドカード文字が含まれていないため、これらの文字列はそのまま残りls、2つの引数test1とで呼び出されますtest2


3
pdkshとksh93は、展開時にブレース展開を実行することに注意してください(グロブの前。noglobではありませんが、ksh93の場合は、braceexpandがオフの場合です!)
StéphaneChazelas

.txt2番目の説明を忘れているようです。
ヴァルはモニカを復活させる

10

展開の順序は次のとおりです。チルダ展開、パラメーターと変数の展開、算術展開、およびコマンド置換(左から右に実行)。単語分割; およびファイル名の拡張。

コマンドの置換後、中括弧の展開は行われません。evalを使用して、次のラウンドの拡張を強制できます。

eval echo $(echo '{1,2}lala')

結果は次のとおりです。

1lala 2lala

6

その問題はに非常に特有です。それは、中括弧の展開をファイル名の展開(グロビング)から分離し、他のすべての展開の前にそれを最初に実行するbashことを決定したためbashです。

bashマンページから:

展開の順序は次のとおりです。チルダ展開、パラメーターと変数の展開、算術展開、およびコマンド置換(左から右に実行)。単語分割; およびパス名の展開。

あなたの例でbashは、それが$(echo ...)遅すぎる場合、コマンド置換()を実行した後にのみ中括弧が表示されます。

これは、パス名展開(グロビング)の直前(および一部として)にブレース展開を実行する他のすべてのシェルとは異なります。これには、cshブレース展開が最初に発明された場所が含まれますが、これに限定されません。

$ csh -c 'ls `echo "test{1,2}.txt"`'
test1.txt test2.txt
$ ksh -c 'ls $(echo "test{1,2}.txt")'
test1.txt  test2.txt

$ var=nope var1=one var2=two bash -c 'echo $var{1,2}'
one two
$ var=nope var1=one var2=two csh -c 'echo $var{1,2}'
nope1 nope2

後者の例では同じでありcshzshksh93mkshまたはfish

また、グロビングの一部としての括弧の拡張は、glob(3)ライブラリー関数(少なくともLinuxおよびすべてのBSDの場合)や他の独立した実装(perl:などperl -le 'print join " ", <test{1,2}.txt>')でも使用できることに注意してください。

なぜそれが別の方法で行われたのかbashは、おそらくその裏に物語がありますが、FWIW論理的な説明を見つけることができず、すべての事後的な合理化は納得できません。


3
perl呼び出すために使用されるcsh、それはまだ同じグロブ演算子を認識していることを驚くべきことではありませんので、グロブを展開するcsh
ステファンChazelas

1

してみてください:::

ls $(echo test {1,2} \。txt)

バックスラッシュ付き。それは今動作します。以前のポスターが言ったように、引用符も削除します。ドットは一致するパターン用ではありませんが、ここでは文字通りピリオドとして解釈されます。


(1)「ここで何が起こっているのですか?なぜ{1,2}「パターン」はそのように動作するのですか?この質問は、「コマンドを使用{1,2}して動作する方法を使用してコマンドを取得するにはどうすればよい?ですか?」あなたは間違った質問に答えています。(2)バックスラッシュはそれとは関係ありません。質問のコマンドに含まれていた引用符を削除したため、コマンドは機能します。
G-Manは 'Reinstate Monica'

0

引用符を削除すると機能します

$ ls $(echo test{1,2})
test1  test2

9
コマンド置換の前に展開が行われていますが、これは質問が求めていることではないと思います(何が起こっているのかを比較してください?)。
Michael Homer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.