在Linux中根据模式批量重命名文件

14

我试图使用mv命令完成三件事情,但不确定是否可能?可能需要脚本,不知道如何编写。所有文件都在同一个文件夹中。

1)以v9.zip结尾的文件应该只是.zip(去掉v9)

2)包含下划线的文件名应该改成用破折号连接

3)大写字母和小写字母相邻(或小写字母和大写字母相邻)的文件名应该在它们之间加上空格。 例如MoveOverNow将变成Move Over Now,ruNaway将变成ruN away [A-Z][a-z] 或 [a-z][A-Z] 变成 [A-Z] [a-z] 和 [a-z] [A-Z]


我不确定你是否会使用mv来完成这个任务...也许可以考虑一下脚本解决方案,鉴于条件的情况。 - quakkels
2
您最后的观点似乎规定不充分。有什么规则可以确定“ruNaway”应该是“ruN away”还是“ru Naway”? - John Bartholomew
1和2 应该使用 rename 很容易完成。第3个则需要更多的脚本编写。你用什么shell,bash吗? - Shawn Chin
http://theunixshell.blogspot.com/2013/01/bulk-renaming-of-files-in-unix.html - Vijay
5个回答

23

大多数基于Debian/Ubuntu的发行版提供了一个rename命令,该命令是由Robin Barker根据Larry Wall 1998年左右原始代码编写的。

以下是该文档的摘录:

  "rename" renames the filenames supplied according to the rule specified as the first argument.  The perlexpr argument is a Perl expression which is expected to modify the $_ string in Perl for at least some of the filenames
  specified.  If a given filename is not modified by the expression, it will not be renamed.  If no filenames are given on the command line, filenames will be read via standard input.

  For example, to rename all files matching "*.bak" to strip the extension, you might say

          rename 's/\.bak$//' *.bak

  To translate uppercase names to lower, you'd use

          rename 'y/A-Z/a-z/' *
它使用Perl,因此您可以使用Perl表达式来匹配模式,实际上我认为它的工作方式很像tchrist的脚本。

另一个非常有用的批量文件重命名工具集是Oskar Liljeblad的renameutils收集。源代码由自由软件基金会托管。此外,许多发行版(尤其是基于Debian / Ubuntu的发行版)都具有包含这些工具的renameutils软件包。

在其中一个发行版上,您可以使用以下命令安装:

$ sudo apt-get install renameutils

然后,要重新命名文件,只需运行此命令:

$ qmv
它将打开一个文本编辑器,列出文件列表,您可以使用编辑器的搜索和替换功能对它们进行操作。

它将打开一个文本编辑器,列出文件列表,您可以使用编辑器的搜索和替换功能对它们进行操作。


9

我没有测试过这些内容,所以我在命令的前面加了 echo ,这样你可以在运行它们之前尝试一下。等您确认无误后,请去掉echo再真正运行命令。

  1. for f in *v9.zip; do echo mv "${f}" "${f%v9.zip}.zip"; done
    
  2. for f in *_*; do echo mv "${f}" "${f//_/-}"; done
    

针对您的第三个问题,我相信它也可以解决,但是可能需要比原始shell一行命令更复杂的方法,正如@tchrist所提到的那样。


1
+1 因为第一行帮助我解决了这个问题的简单版本。谢谢。 - TecBrat
1
这正是我所需要的。它使我能够整理命令,直到完美无缺,然后删除回显并“启动”! - ABrowne

8

我最喜欢的解决方案是我的自己编写的rename脚本。最简单的示例可以映射到你的问题:

% rename 's/_/-/g' *
% rename 's/(\p{Lower})(\p{Upper})/$1 $2/g' *

尽管我非常讨厌文件名中的空格,特别是垂直空格:
 % rename 's/\s//g' *
 % rename 's/\v//g' *

等等。它基于由Larry Wall编写的脚本,但扩展了选项,例如:

usage: /home/tchrist/scripts/rename [-ifqI0vnml] [-F file] perlexpr [files]
    -i          ask about clobbering existent files
    -f          force clobbers without inquiring
    -q          quietly skip clobbers without inquiring
    -I          ask about all changes
    -0          read null-terminated filenames
    -v          verbosely says what its doing 
    -V          verbosely says what its doing but with newlines between old and new filenames
    -n          don't really do it
    -m          to always rename
    -l          to always symlink
    -F path     read filelist to change from magic path(s)

正如你所看到的,它不仅可以使用相同的模式更改文件名,还可以更改符号链接指向的位置。虽然通常会使用s///模式,但您不必使用它。

该目录中的其他工具主要用于Unicode工作,其中有一些非常有用。


1
哇,我不确定我是否有合适的许可证拥有这种极端的能力。非常感谢! - Josh Bond
2
training.perl.com/scripts/rename 的链接已经失效。 - Charity Leschinski

3
以上答案适用于Debian、Ubuntu等系统。
对于RHEL等系统:将文件从from_pattern重命名为to_pattern。

2

我认为链接已经失效,我在Webarchive中找不到tchrist帖子中重命名脚本的页面,所以这里提供另一个Perl脚本。

#!/usr/bin/perl
# -w switch is off bc HERE docs cause erroneous messages to be displayed under
# Cygwin
#From the Perl Cookbook, Ch. 9.9
# rename - Larry's filename fixer
$help = <<EOF;
Usage: rename expr [files]

This script's first argument is Perl code that alters the filename 
(stored in \$_ ) to reflect how you want the file renamed. It can do 
this because it uses an eval to do the hard work. It also skips rename
calls when the filename is untouched. This lets you simply use 
wildcards like rename EXPR * instead of making long lists of filenames.

Here are five examples of calling the rename program from your shell:

% rename 's/\.orig$//'  *.orig
% rename 'tr/A-Z/a-z/ unless /^Make/'  *
% rename '$_ .= ".bad"'  *.f
% rename 'print "$_: "; s/foo/bar/ if <STDIN> =~ /^y/i'  *
% find /tmp -name '*~' -print | rename 's/^(.+)~$/.#$1/'

The first shell command removes a trailing ".orig" from each filename.

The second converts uppercase to lowercase. Because a translation is
used rather than the lc function, this conversion won't be locale-
aware. To fix that, you'd have to write:

% rename 'use locale; $_ = lc($_) unless /^Make/' *

The third appends ".bad" to each Fortran file ending in ".f", something
a lot of us have wanted to do for a long time.

The fourth prompts the user for the change. Each file's name is printed
to standard output and a response is read from standard input. If the
user types something starting with a "y" or "Y", any "foo" in the 
filename is changed to "bar".

The fifth uses find to locate files in /tmp that end with a tilde. It 
renames these so that instead of ending with a tilde, they start with
a dot and a pound sign. In effect, this switches between two common 
conventions for backup files
EOF

$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接