Zsh
Zsh 在查找命令中使用數組
我想
rsync
處理幾個用數組指定的文件,然後刪除目錄中的任何其他文件。我能想到的唯一方法是使用
find
, 和文件刪除其他文件rsync
,因此我們複製盡可能少的文件。在以下範例中,我想刪除 中的任何其他文件
/tmp/tmp/
,除了btrfs_x64.efi
和iso9660_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
.