我发现在管道中使用 find 然后使用 grep -v 来过滤文件而不是开发复杂的正则表达式模式要容易得多。但是,当我像这样通过管道将某些内容传递给 zmv 时:
find | grep -v TFLM | zmv "(*)" "TFLM \$1"
它只是忽略输入并继续将转换应用于所有文件。有没有办法告诉它使用管道输入?我想我可以移走过滤掉的文件,然后使用 zmv,但这并不是真正的解决方案。
答案1
zmv
不从标准输入读取。
我可能会在这里使用find
with mv
,或者zmv
使用zsh
文件名 glob ,但不会两者都使用,并且grep
根本不涉及。grep
应该对分成行的文本而不是文件名(可能包括嵌入的换行符)进行使用。
使用文件名 glob(仅作用于当前目录,并且仅作用于非隐藏文件):
zmv '^TFLM *' 'TFLM $f'
递归地,不重命名目录,包括隐藏文件和隐藏目录中的文件,如下find
所示:
zmv '(**/)(^TFLM *)(#qD^/)' '${1}TFLM $2'
使用find
(但没有 的冲突处理zmv
,因此添加一个-i
安全选项):
find . ! -type d ! -name 'TFLM *' -exec sh -c '
for pathname do
mv -i "$pathname" "${pathname%/*}/TFLM ${pathname##*/}"
done' sh {} +
在bash
(仅适用于当前目录,不包括隐藏文件):
shopt -s extglob
for name in !(TFLM *); do
mv -i -- "$name" "TFLM $name"
done
或者,bash
使用 Perlrename
实用程序:
shopt -s extglob
rename 's|/|/TFLM |' ./!(TFLM *)
(如果没有./
,如果文件名以 开头,某些变体将失败-
。并非所有变体都支持--
标记选项结尾)。
答案2
你所做的并不是如何工作find
,grep
而是zmv
如何工作。首先,您用于find
搜索文件,然后grep
搜索模式;这没有任何意义。该命令find
具有内置模式匹配,例如GNU find
从基本开始-name
到-iname
、-path
等等-regex
。如果您愿意,您甚至可以更改正则表达式的语法,使用-regextype
.这不仅是你做的事情不快或者涉及太多命令,最糟糕的是你的命令很容易出错,例如如果文件内部有空间。
更好的是纯粹find
使用-exec
选项后跟外部命令,如mv
.只要小心谨慎,这个解决方案就可以在不同的系统之间非常方便地移植。
但是,既然您正在使用它zsh
,那么它就需要使用它的所有荣耀,所以只需添加-vn
选项zmv
并尝试不同的模式,很可能您想要
zmv -vn '(^(*TFLM*))' 'TFLM $1'
-v
意味着详细并-n
阻止执行,仅打印将要执行的操作(这对于测试非常有用)。
答案3
我的工作方式与你类似,我更喜欢将grep
命令分层到最后。很难抗拒这种冲动,但在这种情况下,你必须这样做,或者在心里记住,当你想开始按照清单采取行动时,find | ...
你必须开始拉进来xargs
。当您到达这一点时,就该切换到find <regex> -exec ...
.
在您的场景中,您可能会考虑在此处使用的模式如下所示:
$ find . ! -name "*TFLM*" -exec zmv "{}" "TFLM {}" \;
但这是行不通的,根据 @StephaneChazelas 的评论:
由于zmv是zsh函数,所以不能通过find直接执行。即使有人围绕 zmv 制作了一个独立的脚本包装器,将其称为 -exec zmv "{}"...也没有多大意义(完全违背了 zmv 的目的),并且会引入命令注入漏洞
因此,您只剩下更传统的选择,即使用 U&L 问答中所示的方法之一,标题为:批量重命名文件。
或者zmv
直接使用本身进行重命名。既然您正在使用zsh
,很可能您甚至根本zmv
不需要寻求帮助。find
$ zmv "(^*TFLM*)" "TFLM \$1"
笔记:请对我的建议持保留态度zmv
。zsh
我实际上并不使用 Zsh,我通常整天都在 Bash 中。