sim*_*ack 4 zsh array parameter
我想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 {} +
Run Code Online (Sandbox Code Playgroud)
我希望扩展扩展为以下命令:
$ find /tmp/tmp/drivers_x64/ ! -name btrfs_x64.efi ! -name iso9660_x64.efi -type f -exec rm -f {} +
Run Code Online (Sandbox Code Playgroud)
但它似乎正在运行以下命令:
$ find /tmp/tmp/drivers_x64/ "! -name btrfs_x64.efi" "! -name iso9660_x64.efi" -type f -exec rm -f {} +
Run Code Online (Sandbox Code Playgroud)
有没有办法获得前者?理想情况下,如果某些数组条目中有空格,它也可以工作。
是的,在这里您需要为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 {} +
Run Code Online (Sandbox Code Playgroud)
"${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 {} +
Run Code Online (Sandbox Code Playgroud)
或者使用$'\0'
而不是/
因为它无论如何都不能在参数中传递给外部命令:
set -o extendedglob # for (#m)
find ${refind_efi_dir}drivers_x64/ \
${(@0)${drivers//(#m)[?*[\\]/\\$MATCH}/#/!$'\0'-name$'\0'} \
-type f -exec rm -f {} +
Run Code Online (Sandbox Code Playgroud)
但这对易读性没有多大帮助......
在这里,您还可以zsh
对所有内容使用's glob:
(cd -P -- $refind_efi_dir && rm -f -- **/^(${(j[|])~${(b)drivers}})(D.))
Run Code Online (Sandbox Code Playgroud)
凡b
标志逃脱zsh的水珠,如果运营商中的任何$drivers
元素,j[|]
加入他们|
和~
力量的结果将被视为一个glob模式,在这里与否定^
。D
包含隐藏文件,.
限制为常规文件,例如您的-type f
.