Zsh

Zsh 在查找命令中使用數組

  • September 17, 2021

我想rsync處理幾個用數組指定的文件,然後刪除目錄中的任何其他文件。

我能想到的唯一方法是使用find, 和文件刪除其他文件rsync,因此我們複製盡可能少的文件。

在以下範例中,我想刪除 中的任何其他文件/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 {} +

有沒有辦法得到前者?理想情況下,如果某些數組條目中有空格,它也可以工作。

是的,在這裡您需要為find數組的每個元素生成 3 個參數。也find’s-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',而不是/因為它不能在參數中傳遞給外部命令:

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

但這對易讀性沒有多大幫助……

在這裡,您還可以對所有內容使用zsh’s glob:

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

參數j[|]擴展標誌將$drivers數組的元素與|~導致|將其視為全域運算符。該模式被否定^(您需要該extendedglob選項)。D包括隱藏文件,.限制為正常文件,例如您的-type f.

引用自:https://unix.stackexchange.com/questions/651134