14

次のようなファイルがいくつかあります。

/path/with spaces/{a,b,c}/*.gz

そして、ディレクトリのサブセットの下にあるグロブに一致するすべてのファイルa,b,cが、単一のコマンドの引数として終了する必要があります。

mycmd '/path/with spaces/a/1.gz' '/path/with spaces/a/2.gz' '/path/with spaces/c/3.gz' ...

私が気にかけているディレクトリは、コマンド ライン パラメータとして入力され、配列に含まれています。

dirs=( "$@" )

そして、私は次のようなことをしたい:

IFS=,
mycmd "/path/with spaces/{${dirs[*]}}/"*.gz

ただし、bash は変数の前に中括弧を展開するため、これは機能しません。echoand and lsand even eval(*shudder*) でトリックを試しましたが、ファイル名にスペースを使用してそれらを機能させるのは困難です。findブレースを行わないため、あまり役に立たないようです。次のようにして、配列内のディレクトリごとに個別のグロブを取得できます。

dirs=( "${dirs[@]/#//path/with spaces/}" )
dirs=( "${dirs[@]/%//*.gz}" )

ただし、bash は展開時にワイルドカードを引用します。

だから:変数ブレースとグロブパターンに一致するすべてのファイルを取得し、スペースを適切に処理するエレガントな方法はありますか、それともforループで立ち往生していますか?それが違いを生む場合、私はBash 3を使用しています。

4

3 に答える 3

12

スペースを含むパスでブレース展開とグロビングを実行するには、パスのスペースを含む部分を引用できます。

mycmd '/path/with spaces/'{a,b,c}/*.gz

変数の値のリストを使用してブレース展開を行うのは、他の展開よりも前にブレース展開が行われるため、少し注意が必要です。dreaded を使用する以外に方法はありませんeval

eval mycmd "'/path/with spaces/'{a,b,c}/*.gz"

PS ただし、そのような場合、上記のアプローチではなく、ループを使用して引数リストを作成することを個人的に選択します。より冗長ですが、ループは初心者にとって非常に読みやすく、使用する必要がなくなりますeval(特に、展開候補がユーザー入力から派生する場合!)。


コンセプトの証明:

引数の数と各引数を出力するダミー コマンド (x.sh) を使用します。

[me@home]$ shopt -s nullglob # グロビングが一致しない場合の処理

[me@home]$ ./x.sh 'path with space'/{a,b}/*.txt
引数の数 = 3
- space/a/1.txt を含むパス
- space/b/2.txt を含むパス
- space/b/3.txt を含むパス

[me@home]:~/temp$ dirs="a,b"
[me@home]k:~/temp$ eval ./x.sh "'path with space'/{$dirs}/*.txt"
引数の数 = 3
- space/a/1.txt を含むパス
- space/b/2.txt を含むパス
- space/b/3.txt を含むパス
于 2013-01-17T15:20:39.240 に答える
4

さて、これは「ブレース」とfindグロブにbash を使用したものです。

find "${dirs[@]/#//path/with spaces/}" -name '*.gz' -print0 | xargs -0 mycmd

配列の結果が必要な場合に便利です。

于 2013-01-17T15:21:04.150 に答える
2

GNU Parallelファン向けの 1 つを次に示します。

parallel -Xj1 mycmd {}/*.gz ::: "${dirs[@]/#//path/with spaces/}"
于 2013-01-17T16:11:44.030 に答える