如何通过替换文件/目录名称中的f o o
片段来批量重命名许多文件和/或目录?b a r
对于每个建议的方法,最好回答以下问题。
- 在进行实际重命名之前是否可以预览命令的结果?如何?
- 该方法是否仅适用于前缀、仅适用于后缀,还是两者都适用?
- 重命名是仅影响目录、仅影响文件还是同时影响目录和文件?
- 子目录中的文件/目录也会被重命名吗?
替换前缀,示例
为了使任务更加具体,假设类似的文件
o l d prefix file 1.c
o l d prefix file 1.h
o l d prefix file 2.c
o l d prefix file 2.h
应重命名为
n e w prefix file 1.c
n e w prefix file 1.h
n e w prefix file 2.c
n e w prefix file 2.h
还假设在同一目录中存在名为
o l d prefix, dir 1 _
o l d prefix, dir 2 _
这些目录也会被重命名吗?
您可以调整您的方法以仅重命名目录(而不是文件)吗?
或者仅重命名文件(而不是目录)?
替换后缀
还可以考虑重命名后缀在文件中,以便
file 1, o l d suffix
和分别file 2, o l d suffix
重命名为
file 1, n e w suffix
和file 2, n e w suffix
。
对于目录也是如此。分别将
dir 1., o l d suffix
和重命名dir 2., o l d suffix
为
dir 1., n e w suffix
和dir 2., n e w suffix
。
推荐方法?
您推荐什么重命名方法?
笔记
注意添加名称的前缀或后缀只是更通用的特殊情况替换前缀或后缀的情况,即原始前缀或后缀恰好为空字符串的情况。类似地,情况去除前缀或后缀也是替换前缀或后缀的特殊情况,即新的前缀或后缀为空字符串的情况。
更多需要考虑的问题
我知道重命名文件时需要考虑其他更高级的问题,例如添加或删除日期或序列号和/或主题,如下面参考文献中的最后五个问题。
我邀请您提出有关重命名文件/目录(或符号链接)的任何问题,并在您的答案中构建一个合适的示例。
写答案时,不要觉得你必须回答全部这里提出的案例!
随意只关注一特定情况(上述情况之一,或您选择的其他情况),如果您愿意的话。
参考
答案1
0. 寻求通用解决方案1
为了方便未来的自己和其他读者,我将重点关注通用的解决方案。
为了简单起见,我假设有不引号 – 没有双引号 ( "
) 和单引号 ( '
) – 在任何文件/目录名称。
2
作为第一个示例,我将展示如何使用模式将文件重命名
o l d prefix file *.*
为
n e w prefix file *.*
,
从而即使文件名中有空格也重命名前缀。
我也对重命名目录感兴趣,因此会考虑将目录
o l d prefix, dir 1 _
和分别重命名o l d prefix, dir 2 _
为
n e w prefix, dir 1 _
和n e w prefix, dir 2 _
。
其次,我将展示如何替换后缀。例如,文件
file 1, o l d suffix
和分别file 2, o l d suffix
重命名为
file 1, n e w suffix
和file 2, n e w suffix
。
再次,我想看看这如何影响(或不影响)目录。
因此,我还将检查目录
dir 1., o l d suffix
和是否分别dir 2., o l d suffix
重命名为
dir 1., n e w suffix
和dir 2., n e w suffix
。
3
上述所有文件和目录都包含在 zip 文件中:
http://user.it.uu.se/~hesc0353/Files-&-dirs-SEunix-A690768.zip。
4
笔记。
下面的解决方案中出现echo
意味着不会发生重命名。
这是一项既定技术预览在您决定进行重命名之前。
一旦预览看起来不错,只需删除echo
并再次运行命令即可执行实际的重命名。
5
1. 使用 for 循环的通用解决方案
重命名字首表示替换o l d prefix
为n e w prefix
:
6
for f in "o l d prefix"*; do\
echo mv "$f" "n e w prefix""${f#o l d prefix}"; done
我选择搜索以o l d pref
.
重命名后缀, 尝试 :
for f in *"l d suffix"; do\
echo mv "$f" "${f%o l d suffix}""n e w suffix"; done
重命名是仅影响目录、仅影响文件还是同时影响目录和文件?
– 此方法更改的名称两个都文件和目录。
如果这不是您想要的,请尝试find ... -type ... -exec
下一节中的方法。
子目录中的文件/目录也会被重命名吗?
– 不会。使用上述命令之一作为模板不会影响任何子目录中的文件/目录。如果您想这样做,您将必须有意识地对该方法进行相当多的调整。
例如,请参阅第一个解决方案这个答案。
2. 使用通用解决方案find ... -exec mv
下面的方法find ... -exec mv
为您提供了重命名文件的选项仅有的或目录仅有的– 通过-type
旗帜。还可以对其进行调整,以控制命令应在子目录树中搜索文件或目录的深度 - 通过标志
-maxdepth
。
重命名前缀
以下命令替换o l d prefix
为n e w prefix
, 但对于
仅目录。每个文件都可以在单独的子 shell 中重命名,但是通过在内部使用 for 循环-exec
(并-exec
用sh {} +
而不是结束{} \;
),命令运行得更有效:
find . -maxdepth 1 -type d -name "o l d pr*" -exec sh -c\
'for n; do echo mv "${n#./}" "n e w pre${n#./o l d pre}"; done' sh {} +
如果你想重命名仅文件,只需使用-type f
代替
-type d
(易于记住:f
对于文件,d
对于目录)。
重命名后缀
同样,这里是如何替换后缀在大量的文件:
find . -maxdepth 1 -type f -name "*d suffix" -exec sh -c\
'for n; do echo mv "$n" "${n%o l d suffix}n e w suffix"; done' sh {} +
说明
find .
在当前目录及其子目录中搜索。-maxdepth 1
做不是在任意子目录中搜索。-type f
仅查找文件(不包括目录)。-name "*d suffix"
仅搜索以 . 结尾的文件d suffix
。-exec sh -c '...'
在子 shell 中执行,允许命令替换,$(...)
.-exec sh -c 'for n; do mv ...' sh {} +
-exec sh -c 'mv ...' {} \;
比其他方式做同样的事情 更有效率。 7{}
持有任何find
发现的东西。echo
输出命令的结果 - 当您对结果感到满意时,
删除echo
并再次运行命令。mv "sou rce" "dest in"
执行实际的重命名,用新名称
替换旧名称。sou rce
dest in
%
看POSIX shell 模式过滤。done
结束 for 循环。sh {} +
如前所述,sh {} +
关闭该-exec sh -c
子句。
改名两个都文件和目录
故意重命名两个都文件和目录一次性完成,只需省略-type
:
find . -maxdepth 1 -name "o l d pr*" -exec sh -c\
'for n; do echo mv "${n#./}" "n e w pre${n#./o l d pre}"; done' sh {} +
子目录中的文件/目录也会被重命名吗?
该-maxdepth 1
子句确保子目录树中的文件/目录不会受到影响。
如果您故意要重命名后缀全部文件在全部
子目录,这是一个例子:
find . -type f -name "*d suffix" -exec sh -c\
'for n; do echo mv "$n" "${n%o l d suffix}n e w suffix"; done' sh {} +
一句警告。
这个方法将不是用于在一个命令中重命名许多不同子目录中的前缀。
3. 使用Perl rename的解决方案
本节专门针对那些有以下情况的人: Larry Wall 重命名 Perl 安装在您的系统上(或知道如何安装)。 8
rename
我喜欢将Perl 脚本 重命名为 的谨慎做法prename
,以避免将其与
Linux重命名。
该方法是否仅适用于前缀、仅适用于后缀,还是两者都适用?
事实上,您无需关心是重命名前缀还是后缀,这使得 Perl 重命名易于使用。
例如,要替换o l d prefix
为n e w prefix
,请执行以下操作:
prename -n 's/o l d prefix/n e w prefix/' ./"o l d p"*
其中-n
标志产生一个预览。
一旦结果符合您的要求,只需删除该-n
标志并再次运行该命令即可。
重命名是仅影响目录、仅影响文件还是同时影响目录和文件?
和第1节的for循环方法一样,运行prename
会重命名两个都目录和文件。
但是,您可以选择通过if -f
在重命名字符串末尾添加来仅重命名文件(不包括目录),如下所示:
9
prename -n 's/o l d prefix/n e w prefix/ if -f' ./"o l d p"*
如果您只想重命名目录(不包括文件),请使用if !-f
:
prename -n 's/o l d prefix/n e w prefix/ if !-f' ./"o l d p"*
子目录中的文件/目录也会被重命名吗?
我发现 – 当使用正斜杠 ( /
) 作为分隔符时 – Perl 重命名将仅重命名当前工作目录中的文件/目录,而不重命名任何子目录中的文件/目录。
如果您使用其他字符作为分隔符,您实际上可以用来prename
重命名子目录树中的文件/目录。
第二种解决方案是这个答案就是这种相当非正统做法的一个例子。
更正常的做法是find ... -execdir
与 结合起来prename
。
对于这样的示例,请参见
这个答案。
4. 重命名文件或目录的其他好选择
如果您不喜欢上述任何方法,请考虑使用
sed
或awk
(可能与 结合使用xargs
)。
参考
- 如何在 Windows 上安装 MSYS2
- 适用于 Linux 的 Windows 子系统 (WSL)
- 文件名中禁止使用 ASCII 字符
- POSIX shell 模式过滤
- 参数扩展
- 使用 Bash 重命名文件,删除前缀和后缀
- 在最深层重命名许多目录
- 内部的 for 循环
find ... -exec
是可选的,但效率更高 - 包含此答案中使用的文件和目录的 Zip 文件
- 如何终止调用的 shell 命令
-exec
- Perl rename.pl 作者:Larry Wall
- Linux 重命名的手册页
- 使用标志
-n
预览结果prename
- 使用
-f
,以便仅重命名常规文件(而不是目录) - [使用深度优先搜索 Perl 重命名文件和目录] https://unix.stackexchange.com/a/366786)
sed
awk
xargs
1在测试这个答案中提供的命令/解决方案时,我既没有使用正版Linux,也没有使用正版Unix,而是使用了Windows 10上的MSYS2,它可以说是在Microsoft Windows上运行的模拟arch-Linux。当然,对于像我这样的 Windows 用户来说,一个可行的替代方案是使用
适用于 Linux 的 Windows 子系统 (WSL)。
我使用 MSYS2 因为我发现它方便且易于使用。
2
如果有疑问,在考虑任何重命名之前,请检查 命令ls *\"*
和的结果ls *\'*
。
或者更好的是:find . -name '*"*'
和find . -name "*'*"
。
我认为在文件/目录名称中使用引号肯定是自找麻烦。
这个答案列出文件/目录名称中禁止使用的字符。
– 对于 Linux/Unix,只有一个禁用字符:正斜杠 ( /
)。
3我会的不是目标是找到一种按照问题中的要求一次性更改前缀和后缀的解决方案 使用 Bash 重命名文件,删除前缀和后缀。 (如果您需要重命名前缀和后缀,我建议在一个命令中替换其中一个,然后在另一个命令中替换另一个。)
4我鼓励读者下载 zip 文件并将其解压缩到某个(空)目录,然后尝试我在此答案中提供的所有命令。
5对于包含空格的文件和目录,预览可能看起来不正确,因为它缺少周围的双引号 ( "
)。删除echo
仍然会使命令正确运行。
(不要太从字面上理解预览!)
6我使用反斜杠 ( \
) 对长命令进行换行,这样读者就不需要水平滚动。当您自己构建一个具体示例时,我建议删除反斜杠并将整个命令写在一行中。
7{} +
要了解更多关于和 之间的区别{} \;
,请参阅示例
如何终止调用的 shell 命令-exec
(及其参考文献)。
8尝试在终端中 输入rename
或(然后按)。如果安装了 Perl rename,预计会看到 或类似的内容 – 其中包含该单词。 如果未安装,预计会看到类似的内容 。 您可以尝试的另一件事是。prename
EnterUsage: rename [-v] [-n] [-f] perlexpr [filenames]
perlexpr
bash: prename: command not found
which prename
9 这条评论说该
if -f
子句还将重命名符号链接。如果不重命名符号链接,
它建议改用它。if (-f && ! -l)