web-dev-qa-db-ja.com

Bashスクリプトの変数にグロブ式を割り当てる方法は?

次の2行のコードがbashスクリプトで実行されると、「ls」はファイルが存在しないことを報告します。

dirs=/content/{dev01,dev02}
ls -l $dirs

-xオプションを指定してスクリプトを実行すると、変数が一重引用符で囲まれているように見えます(グロブを防止します)。

+ dirs=/content/{dev01,dev01}
+ ls -l '/content/{dev01,dev01}'
ls: /content/{dev01,dev01}: No such file or directory

対話型シェル(引用符を除く)から「ls」コマンドを実行すると、2つのディレクトリが返されます。

私はBashリファレンスマニュアル(v 3.2)を読んでいて、ファイル名の展開が行われない理由(-fをシェルに渡していない)、またはそれを確実にするために設定できるものを確認できませんグロビングが発生します。

42
kdgregory

私はそれが展開の順序だと思います:

展開の順序は次のとおりです:brace expansion、チルダ展開、パラメーター、variableおよび算術展開とコマンド置換(左から右に実行)、ワード分割、およびpathname expansion

したがって、変数が置換されると、中括弧の展開は行われなくなります。これは私にとってはうまくいきます:

eval ls $dirs

Evalには十分注意してください。それはそのままのものを実行します。したがって、dirsにf{m,k}t*; some_commandが含まれている場合、lsが終了した後でsome_commandが実行されます。現在のシェルでevalに指定した文字列を実行します。存在するかどうかに関係なく、/content/dev01 /content/dev02をlsに渡します。ものの後に*を置くと、パス名が展開され、存在しないパスが省略されます。

dirs=/content/{dev01,dev02}*

私はこれについて100%確信はありませんが、私には理にかなっています。

ここ は、あなたが何をしようとしているのかについての優れた議論です。

簡単に言えば、配列が必要だということです。

dirs=(/content/{dev01,dev01})

しかし、結果をどうするかは、あなたが目指していたものよりも複雑になる可能性があると思います。

22
feoh

これはファイル名の展開ではなく、中括弧の展開です。違いはわずかですが、存在します。ファイル名の展開では、結果として既存のファイルのみを受け取りますが、ブレース展開では、あらゆる種類の文字列を生成できます。

http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion

http://www.gnu.org/software/bash/manual/bashref.html#Filename-Expansion

今、これは私のために働いたものです:

#!/bin/sh
dirs=`echo ./{dev01,dev02}`
ls $dirs
9
Yoni Roit

(私のような)Googleでこれを見つけた人にとって、@ Peterと@feohの答えは、「bashスクリプトで変数をグロブ化する方法」の一般的な解決策です。

list_of_results=(pattern)

patternに一致する既存のファイル名を配列list_of_resultsに保存します。 list_of_resultsの各要素は、1つのファイル名、スペース、およびすべてを保持します。

各結果には、0から始まる"${list_of_results[<index>]}"<index>としてアクセスできます。リスト全体を"${list_of_results[@]}"として正しく引用符で囲んで取得できます。

7
cxw

私はあなたが必要とするものは配列であると思いますが、それはあなたを新しいバッシに制限するでしょう。 evalを使用するよりも節約されます。

dirs=( /"content with spaces"/{dev01,dev02} )

dirs=( /content/{dev01,dev02} )
ls -l "${dirs[@]}"

/content/{dev01,dev02}

次のように展開されます:

"/content/dev01" "/content/dev02"

これらのディレクトリの存在は、拡張とは無関係です。

ブレース展開に変数を割り当てると、予測できなくなります。

dirs=/content/{dev01,dev02}

に変わるかもしれません

"/content/dev01"

または

"/content/dev01 /content/dev02"

または

"/content/dev01" "/content/dev02"

または

"/content/{dev01,dev02}"

中括弧を何らかの方法で引用すると、展開されないため、結果には中括弧が含まれ、ほとんど意味がなくなります。

2
Peter

ファイルをグロブしたいので、中括弧展開を使用すべきではありません。この場合のブレース展開の使用はアンチパターンであり、ジョブには間違いなく間違ったツールです。

あなたが望むのは extended globbing

shopt -s extglob # likely already set in interactive shells

dirs=/content/@(dev01|dev02)
ls $dirs
1
gniourf_gniourf
ls `echo $dirs` 

cygwinで動作します。

0
Zsolt Botykai

誰も対処していない問題は、変数の割り当てが違いを生むことです。

dirs=/content/{dev01,dev02}

とは異なる展開

echo /content/{dev01,dev02}

問題は、展開の結果をdirsに割り当てる方法です。

参照: 変数宣言でBash置換を使用する方法

0
Sam Liddicott