受到这个问题的启发。简而言之,最初的问题是“如何将所有文件全部:2f
转换-
为文件夹内的所有文件”。例如,如果我有一个文件,./abc:2fdef
它应该重命名为./abc-def
.
起初我认为这是一个简单的任务......find
所有文件然后sed
替换:2f
为-
. 在尝试构建单行时,我想出了以下命令:
find . -type f -name '*:2f*' | xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")
Run Code Online (Sandbox Code Playgroud)
但是它不起作用。经过大量测试,我发现问题出在xargs
部分 - $() 在用文件名xargs
替换地方之前执行{}
。详细说明,
xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")
Run Code Online (Sandbox Code Playgroud)
被评估为($(...)
被评估)
xargs -I {} mv {} {}
Run Code Online (Sandbox Code Playgroud)
进而
mv ./abc:2fdef ./abc:2fdef
Run Code Online (Sandbox Code Playgroud)
这不是我所期待的。所以,我的问题是,{}
在评估$(...)
零件之前,我可以让 xargs 全部替换为文件名吗?
不,因为xargs
在 shell 调用之前不能xargs
用$(…)
已经评估的东西替换某些东西。这是由于shell 扩展的顺序。
我可能会这样做:
find . -type f -name '*:2f*' -exec bash -c 'mv -- "$0" "${0//:2f/-}"' {} \;
Run Code Online (Sandbox Code Playgroud)
在这里,shell 调用是从 找到的每个文件中评估的find
,并且字符串替换是使用 shell 功能完成的,而不是对sed
.
此外,这种方法更安全,因为文件名中的空格得到了正确处理(通过对mv
调用的参数进行双引号)。更多关于这里。
对于这些任务,您可能需要更高效的工具,例如zmv
Zsh 中提供的 ,或rename
与许多 Linux 发行版捆绑在一起的 Perl :
rename 's/:2f/-/' *
Run Code Online (Sandbox Code Playgroud)