灵感来自这个问题。简而言之,原始问题是“如何将文件夹中的所有文件全部转换: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/-/' *