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
无xargs
x
仅在那里直接解决提问者的做法。
{}
直接在shell(sh -c "…"
)命令中使用非常危险-您应该始终将其作为参数传递。(2)并非所有版本的find
支持该{}_renamed
构造。(3)我不理解您的声明xargs
对删除文件(与重命名文件相反)有用。
xargs
不是mv
vs. 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
版本具有与第一个示例相同的效率/