假设我有3个子目录。它们都包含一个名为old_file_name
.现在,通过一个命令,我想将它们全部重命名为new_file_name
.
我试过
sudo find . -name "old_file_name" -exec rename old_file_name new_file_name {} \;
但它显示以下错误:
在(用户提供的代码)使用“strict subs”时不允许使用裸字“new_file_name”。
答案1
perl
的变体首先rename
将一些代码作为参数perl
来转换文件名和文件列表。
在您的尝试中,您将使用old_file_name
(作为perl
代码,这没有什么意义;如果没有use strict
,它只会被视为相同并且"old_file_name"
不会产生任何效果)和new_file_name
并作为要重命名的文件参数找到的文件find
来调用它。
在这里,你可以这样做:
find . -depth -name old_file_name -execdir mv old_file_name new_file_name \;
-execdir
不是标准的,但相当常见。与 相比-exec
,它在每个选定文件的父目录中执行命令,而不是在进程的当前工作目录中执行find
。
没有-execdir
,你可以这样做:
find . -depth -name old_file_name -exec sh -c '
for file do
mv "$file" "${file%/*}/new_file_name"
done' sh {} +
答案2
由于您在这里对文件名进行相当简单的转换,因此我真的认为没有必要使用rename
.同样,由于您知道要重命名的文件位于当前目录的子目录中,并且您似乎知道它们的确切名称,因此find
似乎也没有必要使用。
假设您有许多子目录,每个子目录可能包含一些文件和您的h
文件。
要将每个h
文件重命名为he
,最简单的解决方案是循环遍历它们并将mv
它们更改为新名称。在这种情况下,由于您只是将字符添加e
到名称中,因此变得非常简单:
for name in ./*/h; do
mv -i "$name" "$name"e
done
这将循环通过模式扩展生成的所有路径名./*/h
。对于每个这样的名称,该mv -i
命令用于e
在其末尾添加一个。选项-i
将mv
导致mv
在替换现有名称之前要求确认。
更新问题后更新:
old_file_name
要将每个子目录中调用的所有文件重命名为new_file_name
:
for name in ./*/old_file_name; do
mv -i "$name" "${name##*/}/new_file_name"
done
或者
for name in ./*/old_file_name; do
mv -i "$name" "$( dirname "$name" )/new_file_name"
done
在这两个循环中,必须以这样的方式计算目标名称:它引用与旧文件名所在目录相同的目录中的新文件名。
在第一个循环中,我们使用标准变量替换 找出目录的路径,${name##*/}
这将删除从$name
最后一个到(包括最后一个)的所有内容/
。在第二个循环中,我们使用dirname "$name"
,它的作用几乎相同。然后,我们添加/new_file_name
到结果字符串的末尾以形成新文件名的完整路径名。
最后,使用 Perlrename
实用程序:
rename 's/old_file_name$/new_file_name/' */old_file_name
您的命令遇到的问题是它没有使用 Perl 表达式作为其第一个参数。该rename
实用程序采用一个 Perl 表达式来转换给定的路径名,并将其依次应用于每个路径名。在上面的命令中,我们使用一个简单的替换表达式,将路径名的文件名部分替换为新文件名。
请注意,替换接收完整路径名,因此我们需要确保匹配字符串的结尾(带有$
),以免意外重命名任何路径目录在恰好名为 的路径名中old_file_name
。
答案3
添加到 Stéphane Chazelas 的答案中,
您可能必须使用引号,如果任何文件名包含空格,则必须使用引号,因此old_file_name
变为'old_file_name'
。这似乎通常是这种情况,如果处理许多文件,请使用'{}'
而不是{}
。目前我无法说在使用该选项时引用赞誉是否合适-execdir
。
另外,请检查寻找手册页,因为它有一个安全警告似乎适用于这种情况。