Answers:
以下是您的方法的直接解决方案:
find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;
但是,如果您有很多匹配文件,这将非常昂贵,因为您会mv为每个匹配项启动一个新的shell(执行)。而且,如果您在任何文件名中都有有趣的字符,它将爆炸。一种更有效,更安全的方法是:
find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed
它还具有使用命名不正确的文件的好处。如果find支持的话,可以减少到
find . -type f -name 'file*' -exec mv {} {}_renamed \;
xargs不使用时{},该版本很有用
find .... -print0 | xargs --null rm
在这里rm被调用一次(或多次调用很多文件),但不是每个文件都调用一次。
我删除了basename你的问题,因为它可能是错误的:你会移动foo/bar/file8到file8_renamed,不是foo/bar/file8_renamed。
编辑(如评论中所建议):
find无xargsx仅在那里直接解决提问者的做法。
{}直接在shell(sh -c "…")命令中使用非常危险-您应该始终将其作为参数传递。(2)并非所有版本的find支持该{}_renamed构造。(3)我不理解您的声明xargs对删除文件(与重命名文件相反)有用。
xargs不是mvvs. rm,而是使用{}vs.with。前者与mv file1 file1_renamed; mv file2 file2_renamed后者相似rm file1 file2。
在尝试了第一个答案并进行了一点玩弄之后,我发现可以使用以下方法来做得更短,更简单-execdir:
find . -type f -name 'file*' -execdir mv {} {}_renamed ';'
看起来它也应该完全满足您的需求。
find支持-execdir而{}不是整体的实现,它也是最安全的。您可能希望将添加-i到mv,虽然(和-T如果mv支持的话)
mv提示或除了它之外,您还可以(无疑取决于您find对它的实现是否支持)使用-okdir它来输出要在执行之前执行的命令。
-depth是,如果您还要触摸目录名称,那也是个好主意。
-execdir确实有一个很讨厌的缺点,find拒绝做任何事情,如果PATH包含任何相对路径... askubuntu.com/questions/621132/... find: The relative path XXX is included in the PATH environment
另一种方法是while read在find输出上使用循环。这样就可以将每个文件名作为变量进行访问,而不必担心sh -c使用find的-exec选项生成单独的进程会产生额外的成本/潜在的安全性问题,因此可以对其进行操作。
find . -type f -name 'file*' |
while IFS= read file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
并且,如果所使用的外壳支持-d指定read分隔符的选项,则可以使用以下命令支持名称奇怪的文件(例如,带有换行符):
find . -type f -name 'file*' -print0 |
while IFS= read -d '' file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
我想扩展第一个答案,请注意,由于./路径前缀存在于filename参数中,因此无法将其附加到文件名。
修改Thomas Erker的答案,我发现这是一种更通用的方法
find . -name PATTERN -printf "%f\0" | xargs --null -I{} mv {} "prefix {} suffix"
xargs选项:
--null指示传递的每个参数stdin以空字符(\0)结尾。这样,文件名可以包含空格,否则每个单词将被威胁为mv命令的不同参数。
-I replace-str的每次出现replace-str都会替换为从中读取的参数stdin。因此,如果需要,可以将其更改为其他字符串。
pringf "%f\0"而不是print0?
-print0会产生./前缀,这些PATTERN外壳元字符在重命名为带有原始名称的前缀时会受到阻碍。(例如重命名0 - foo.txt到00 - foo.txt,1 - bar.txt对01 - bar.txt等)
我能够做的类似的东西for,find和mv。
for i in $(find . -name 'config.yml'); do mv $i $i.bak; done
这将找到所有config.yml文件并将其重命名为config.yml.bak
for并执行批量操作。
x没有用的情况下:find . -type f -name 'file*' -exec mv {} "{}_renamed" \;xargs版本具有与第一个示例相同的效率/