find コマンドで配列を使用する Zsh

find コマンドで配列を使用する Zsh

rsync配列で指定されたいくつかのファイルを繰り返し、ディレクトリ内の他のファイルを削除したいと思います。

私が考えることができる唯一の方法は、を使用し、他のファイルを削除しfindrsyncファイルを上書きしてできるだけ少ない数のファイルをコピーすることです。

次の例では、およびを/tmp/tmp/除く他のファイルをすべて削除したいと思います。btrfs_x64.efiiso9660_x64.efi

$ refind_efi_dir='/tmp/tmp/'
$ drivers=('btrfs_x64.efi' 'iso9660_x64.efi')
$ find ${refind_efi_dir}drivers_x64/ "${drivers[@]/#/! -name }" -type f -exec rm -f {} +

拡張を次のコマンドで拡張したいと思います。

$ find /tmp/tmp/drivers_x64/ ! -name btrfs_x64.efi ! -name iso9660_x64.efi -type f -exec rm -f {} +

しかし、次のコマンドを実行しているようです。

$ find /tmp/tmp/drivers_x64/ "! -name btrfs_x64.efi" "! -name iso9660_x64.efi" -type f -exec rm -f {} +

前者を得る方法はありますか?理想的には、配列項目の一部にスペースがある場合にも機能します。

答え1

findはい、ここでは配列の各要素に対して3つのパラメータを生成する必要があります。また、findパターンが必要なので、正確なファイル名と一致させるには、ワイルドカード演算子(、および)をエスケープする必要が-nameあります。find*?[\

set -o extendedglob # for (#m)
exclusions=()
for name ($drivers) exclusions+=(! -name ${name//(#m)[?*[\\]/\\$MATCH})

find ${refind_efi_dir}drivers_x64/ $exclusions -type f -exec rm -f {} +

"${array[@]/pattern/replacement}"各要素に対して置換が実行されると、配列内の要素の数だけ拡張されます。

ここでは-nameファイルが必要だとします。名前パターンにはを含めないでください。各要素をで置き換えてから分割すること/ができます。!/-name/element/

set -o extendedglob # for (#m)
find ${refind_efi_dir}drivers_x64/ \
  ${(@s[/])${drivers//(#m)[?*[\\]/\\$MATCH}/#/!\/-name\/} \
  -type f -exec rm -f {} +

あるいは、とにかく外部コマンドに引数として渡すことはできませんので、$'\0'notを使用してください。/

set -o extendedglob # for (#m)
find ${refind_efi_dir}drivers_x64/ \
  ${(@0)${drivers//(#m)[?*[\\]/\\$MATCH}/#/!$'\0'-name$'\0'} \
  -type f -exec rm -f {} +

しかし、読みやすさにはあまり役に立ちません...

zshここでは の glob を使ってすべてを表すこともできます。

(cd -P -- $refind_efi_dir && rm -f -- **/^(${(~j[|])drivers})(D.))

ここで、パラメータ拡張フラグは配列j[|]要素を使用して連結し、グローバル演算子として処理されるようにします。モードが無効になります(このオプションが必要です)。隠しファイルを含みます。$drivers|~|^extendedglobD.-type f

答え2

"${drivers[@]/#/! -name }"! -name各配列要素に同じシェルワードを入れます。"${=drivers[@]/#/! -name }"結果を分割するので、!およびは-name別のシェルワードで終わりますが、配列要素もスペースに分割されます。

1つの解決策は乱用することですeP グローバル予選:

find … /(e\''reply=($drivers)'\'P\''!'\'P\''-name'\') …

/(…)/常に正確に1つのエントリ(ルートディレクトリ)に一致するglobパターンを展開し、ここにglob修飾子を適用します。 glob修飾子は、e各項目を配列変数の新しい値に置き換えますreply。この値は、後続のglob修飾子が適用される単語のリストに設定されます。次に、glob修飾子を2回使用して、P各一致の前に指定されたテキストを別々の単語として挿入します。

この特定のケースではステファン・チャゼラスが示すように、zsh globを使用すると、findを使用せずにすべての操作を実行できます。

関連情報