次の引数として渡された一連のディレクトリ内のファイルを選択しようとしています。
${@/%/*}
ただし、これは理想的ではありません。スペースのあるパスが壊れ、パラメータ展開を引用するとファイル名の展開が停止するためです。満足のいく解決策は可能ですか?
追伸:これを実行するにはfind -maxdepth
を使用する必要があることは承知していますが、パラメーター展開とグロブを組み合わせるのが非常に難しいように見える理由について知りたいです。
あなたはいつでもすることができます:
_IFS= # don't split
files=(${@/%/*}) # use split+glob upon expansion with split disabled
_
ただし、_"$@"
_にワイルドカード文字が含まれている場合は、そのように解釈されます。また、一致しない各グロブのパターンが展開されない状態になります。
ループとnullglob
オプションを使用して、これらに対処できます。
_shopt -s nullglob
files=()
for arg do files+=("$arg"*); done
_
または、zsh
の代わりにbash
を使用して、次を使用することもできます。
_files=($^argv*(N))
_
_$^array
_は、_$array
_の1つの拡張に対してrcexpandparam
オプションをオンにします。 rc
シェル(およびfish
シェルの場合も同様)では、_$array*
_ここで、_$array
_には2つの要素a
とb
は_a*
_、_b*
_として展開されるため、ここではfiles=($argv[1]*(N) $argv[2]*(N)...)
を実行するようなものです(_$argv[1]
_は_$1
_と同じですが、より冗長です)。 _(N)
_自体は、その1つのグロブのnullglob
動作をオンにするグロブ修飾子です。
fish
シェルでは、次のようになります。
_set files $argv*
_
as fish
は、nullglob
への引数でset
のような動作を有効にし、rc
と同様に配列を展開します。ただし、fish
の構文はbash
の構文とは根本的に異なります。zsh
よりもはるかに異なります。
これらは、_"$1"*
_のように_"$2"*
_、_${@/%/*}
_...グロブを拡張することを目的としていることに注意してください。実際に_"$1"/*
_、_"%2"/*
_...グロブを意味する場合は、引数として渡される一連のディレクトリ内のファイルが示唆するように、_${@/%/\/*}
_が必要です。代わりに、上記のコード部分の_"$arg"/*
_、$^argv/*(N)
、_$argv*
_。
他のグロブ文字をバックスラッシュ+文字に置き換えます。空白文字をバックスラッシュ+文字に置き換えるか、(より堅牢に)IFS
を空の文字列に設定します。前のエスケープステップの結果としてバックスラッシュが再エスケープされないように、最初にバックスラッシュをエスケープすることを忘れないでください。ただし、バックスラッシュはワイルドカード文字がある場合にのみ特別であるため、エスケープするものがない場合は何もエスケープしないでください。
一致するものがない場合は、nullglob
オプションを設定して、展開されていないパターンではなく、空のリストを取得します。関数でこれを行い、シェルオプションとIFS
ローカルへの変更を保持するように調整します。
最小限のテスト:
function set_patterns {
typeset restore_shopt=$(shopt -p nullglob)
shopt -s nullglob
typeset IFS=
typeset x
patterns=()
for x; do
if [[ "$x" == *[*?[]* ]]; then
x="${x//\\/\\\\}"
x="${x//\*/\\*}"
x="${x//\?/\\?}"
x="${x//\[/\\[}"
fi
x="${x//%/*}"
patterns+=($x)
done
eval "$restore_shopt"
}