这个 zsh 解决“参数列表太长”的作用是什么?

这个 zsh 解决“参数列表太长”的作用是什么?

我读到这个答案来自 @Gilles 以下内容:

在 zsh 中,您可以加载mv内置命令:

setopt extended_glob
zmodload -Fm zsh/files b:zf_\*
mv -- ^*.(jpg|png|bmp) targetdir/

作为问题的解决方案"mv: Argument list too long”。答案建议使用 zshmv(与 GNU 相对)但这行代码到底是做什么的?:

zmodload -Fm zsh/files b:zf_\*

答案1

查看 zsh 文档的最佳方法是使用info.

如果你运行info zsh,你可以使用指数(想一个的索引)来定位描述该命令的部分zmodload

i,即可输入zmo并按Tab。您将直接进入zmodload内置描述,它会告诉您所有相关信息。

简而言之,zmodload -F加载模块(如果未加载)并仅启用指定的特征从该模块。

通过,我们在此处启用了匹配模式-m的功能。是针对内置的,因此上面的命令加载模块(有关详细信息,请参阅 参考资料)并且仅启用名称以.mb:zf_*b:zsh/filesinfo -f zsh -n 'The zsh/files Module,'zf_

zmodload -F zsh/files

加载模块,但不启用任何功能:

$ zmodload -FlL zsh/files
zmodload -F zsh/files -b:chgrp -b:chown -b:ln -b:mkdir -b:mv -b:rm -b:rmdir -b:sync -b:zf_chgrp -b:zf_chown -b:zf_ln -b:zf_mkdir -b:zf_mv -b:zf_rm -b:zf_rmdir -b:zf_sync

列出该模块的功能,指定当前启用的功能(目前没有)。您会注意到有 amvzf_mv内置的。

$ zmodload -mF zsh/files 'b:zf_*'
$ zmodload -FlL zsh/files
zmodload -F zsh/files -b:chgrp -b:chown -b:ln -b:mkdir -b:mv -b:rm -b:rmdir -b:sync +b:zf_chgrp +b:zf_chown +b:zf_ln +b:zf_mkdir +b:zf_mv +b:zf_rm +b:zf_rmdir +b:zf_sync

您会注意到zf_mv内置函数已启用,但不是那个内置mv函数(其他内置函数也是如此)。这意味着,这些内置版本的系统命令已启用,但不会覆盖系统命令:

$ type zf_mv
zf_mv is a shell builtin
$ type mv
mv is /bin/mv

现在你已经有了一个内置的mv作为zf_mv,不是mv,你可以这样做:

zf_mv -- ^*.(jpg|png|bmp) targetdir/

因为zf_mv它是内置的,所以没有execve()系统调用,所以您不会达到Too many args与其相关的限制。

当然,你也可以这样做:

zmodload zsh/files # without -F, all the features are enabled
mv -- ^*.(jpg|png|bmp) targetdir/

mv但请注意,它会用内置的等效项替换系统zsh

为了克服E2BIG execve()错误(参数过多执行外部命令时),zsh还提供了一个zargs功能。

你跑:

autoload zargs # in ~/.zshrc if you use it often

将其标记为自动加载。

然后你可以使用:

zargs -- ^*.(jpg|png|bmp) -- mv -t targetdir/

(这里假设 GNUmv作为-t选项)。zargs将运行mv尽可能多的命令以避免 E2BIG(就像xargs会做的那样)。

答案2

有一个不依赖 bashism 的通用解决方案:xargs

xargs从中读取参数流stdin,然后将它们传递给任意指定的实用程序。在你的情况下,命令行应该是这样的:

# find -E /source/dir -iregex ".*\.(jpg|png|bmp)" | xargz -n 1 -J % mv % /target/dir

这里-E意味着find使用现代正则表达式(for|alternatives),-n 1意味着传入流将被分割成单个参数,-J %意味着每个参数将在%字符的下一次出现时被替换。

-J %是必要的,因为xargs默认情况下将参数附加到子命令的末尾。缺少-J %就相当于xargs -n 1 -J % mv /target/dir %那绝对不是你想要的。

相关内容