使用 xargs 和 $() - 运算符优先级?

使用 xargs 和 $() - 运算符优先级?

灵感来自这个问题。简而言之,原始问题是“如何将文件夹中的所有文件全部转换:2f为”。例如,如果我有一个文件,它应该重命名为。-./abc:2fdef./abc-def

起初我以为这是一个简单的任务...find所有文件然后sed替换:2f-。当尝试构建一行时,我想出了以下命令:

find . -type f -name '*:2f*' | xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

但是它不起作用。经过大量测试,我发现问题出在部分 - 在用文件名替换xargs之前执行了 $() 。具体来说,xargs{}

xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

被评价为($(...)被评价为)

xargs -I {} mv {} {}

进而

mv ./abc:2fdef ./abc:2fdef

这不是我所期望的。所以,我的问题是,我可以让 xargs{}在评估$(...)部分之前将所有内容替换为文件名吗?

答案1

不,因为xargs不能用已经求值的 shell 调用之前的内容替换xargs$(…)这是由于shell 扩展

我可能会这样做:

find . -type f -name '*:2f*' -exec bash -c 'mv -- "$0" "${0//:2f/-}"' {} \;

这里,从 找到的每个文件中评估 shell 调用find,并完成字符串替换具有外壳特征而不是再次调用sed

此外,这种方法更安全,因为文件名中的空格得到了正确处理(通过双引号将参数括起来mv)。有关更多信息这里


对于这些任务,您可能需要一个更高效的工具,例如zmv,可在 Zsh 中使用,或 Perl rename,与许多 Linux 发行版捆绑在一起:

rename 's/:2f/-/' *

相关内容