我在 OS X 上定义了一个名为 的函数,finderpackage
该函数尝试根据 Finder 确定文件夹实际上是否是“包”(也有点错误地称为“包”)。
我的预期用途是限制find
进入此类文件夹,这有时很有用。
一个应用程序将查找子树中文件的大小,同时处理实际上是文件夹的应用程序、框架、文档格式,并且类似于单个“文件”,就像 Finder 一样:
find . -xdev \( -exec finderpackage {} \; -exec du -sk {} \; -prune \) -or \( -type f -exec du -k {} \; \)
然而,这个例子并不能像find
抱怨的那样工作:find: finderpackage: No such file or directory
我可以不以这种方式使用 zsh 函数吗?
(当然我可以将其重写为脚本,我只是好奇我是否错过了有关如何使用函数的一些内容?)
答案1
函数是 shell 语言的特性。/bin/zsh
是一个命令,是zsh
语言的解释器。find
是另一个旨在查找文件的命令。有了-exec
,就可以执行一个命令。 zsh 函数不是命令。
find
需要zsh
解释函数中的代码。为此,它需要zsh
以某种方式调用,告诉它加载该函数的代码并使用它找到的文件运行它。可以这样做,例如:
find ... -exec zsh -c "(){$functions[finderpackage];}"' "$@"' zsh {} \; ...
(在上面,我们zsh
使用内联脚本(with -c
)进行调用,其内容使用匿名函数((){code} args
),其中代码是从finderpackage
调用该命令的 shell 中的函数的代码复制而来的find
)。
但这意味着zsh
每个文件调用一个命令,这将是非常低效的。
zsh
globbing 具有递归功能和限定符,这使得它几乎等同于,find
但不幸的是,它缺少的一件事是控制如何以任意方式完成目录遍历的能力。
您可以根据名称修剪目录,例如:
setopt extendedglob
print -rl -- (^*.pkg/)#*(.)
到修剪目录*.pkg
。但是你不能修剪那些目录老的或者例如包含这个或那个文件。为此,您必须手动进行目录遍历。
find
你可以做的一件事是作为 a进行交互coproc
并使用它,尽管这也不会非常有效-ok
:
coproc stdbuf -o0 find . -type f -exec printf 'f:%s\0' {} \; -o \
-type d -exec printf 'd:%s\0' {} \; -ok true \; -prune 2> /dev/null
while IFS=: read -rpd '' type file; do
case $type in
(d)
if finderpackage $file; then
print -p y
du -sk $file
else
print -p n
fi;;
(f)
du -k $file
esac
done