根据模式重命名 Linux 中的大量文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6316600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:27:24  来源:igfitidea点击:

Renaming lots of files in Linux according to a pattern

linuxsysadmin

提问by Josh Bond

I'm trying to do three things with the mv command, but not sure it's possible? Probably need a script. not sure how to write it. All files are in same folder.

我正在尝试使用 mv 命令做三件事,但不确定是否可行?可能需要一个脚本。不知道怎么写。所有文件都在同一个文件夹中。

1) Files ending with v9.zip should just be .zip (the v9 removed)

1) 以 v9.zip 结尾的文件应该只是 .zip(删除了 v9)

2) Files containing _ should be -

2) 包含 _ 的文件应该是 -

3) Files with Uppercase letter next to a lowercase letter (or lowercase next to an Uppercase) should have a space between them. So MoveOverNow would be Move Over Now and ruNaway would be ruN away [A-Z][a-z] or [a-z][A-Z] becomes [A-Z] [a-z] and [a-z] [A-Z]

3) 小写字母旁边的大写字母(或大写字母旁边的小写字母)的文件之间应该有一个空格。所以 MoveOverNow 将是 Move Over Now 并且 ruNaway 将 run away [AZ][az] 或 [az][AZ] 变为 [AZ] [az] 和 [az] [AZ]

采纳答案by tchrist

My favorite solution is my own renamescript. The simplest example that maps to your problems are these:

我最喜欢的解决方案是我自己的重命名脚本。映射到您的问题的最简单示例如下:

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

Although I really hate whitespace in my filenames, especially vertical whitespace:

虽然我真的很讨厌文件名中的空格,尤其是垂直空格:

 % rename 's/\s//g' *
 % rename 's/\v//g' *

et cetera. It's based on a script by The Larry Wall, but extended with options, as in:

等等。它基于 The 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)

As you see, it can change not just the names of files, but where symbolic links are pointing to using the same pattern. You don't have to use a s///pattern, although often one does.

如您所见,它不仅可以更改文件名,还可以使用相同的模式更改符号链接指向的位置。您不必使用s///模式,尽管经常使用。

The other tools in that directoryare mostly for Unicode work, of which there are some super-useful ones.

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

回答by John Zwinck

I haven't tested these, so I put echoat the front of the commands so you can try them before removing the echo to run them for real.

我还没有测试过这些,所以我把它们放在echo命令的前面,这样你就可以在删除回声以真正运行它们之前尝试它们。

1)

1)

for f in *v9.zip; do echo mv "${f}" "${f%v9.zip}.zip"; done

2)

2)

for f in *_*; do echo mv "${f}" "${f//_/-}"; done

As for your third problem I'm sure it can be done too but maybe a more sophisticated approach than raw shell one-liners will help, as @tchrist mentioned.

至于你的第三个问题,我相信它也可以完成,但正如@tchrist 提到的那样,也许比原始外壳单行更复杂的方法会有所帮助。

回答by james-geldart

The above answers apply to Debian, Ubuntu etc

以上答案适用于 Debian、Ubuntu 等

For RHEL and co: rename from_pattern to_pattern files

对于 RHEL 和 co:将 from_pattern 重命名为_pattern 文件

回答by Anthony Michael Cook

There's a renamecommand provided with most Debian/Ubuntu based distros which was written by Robin Barker based on Larry Wall's original code from around 1998(!).

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

Here's an excerpt from the documentation:

以下是文档的摘录:

  "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/' *
  "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/' *

It uses perl so you can use perl expressions to match the pattern, in fact I believe it works much like tchrist's scripts.

它使用 perl,因此您可以使用 perl 表达式来匹配模式,实际上我相信它的工作方式与 tchrist 的脚本非常相似。

One other really useful set of tools for bulk file renaming is the renameutils collection by Oskar Liljeblad. The source code is hosted by the Free Software Foundation. Additionally many distros (especially Debian/Ubuntu based distros) have a renameutilspackage with these tools.

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

On one of those distros you can install it with:

在这些发行版之一上,您可以使用以下命令安装它:

$ sudo apt-get install renameutils

And then to rename files just run this command:

然后重命名文件只需运行以下命令:

$ qmv

It will pop open a text editor with the list of files, and you can manipulate them with your editor's search and replace function.

它将弹出一个带有文件列表的文本编辑器,您可以使用编辑器的搜索和替换功能操作它们。

回答by Charity Leschinski

I think the link is broken and I couldn't find the page in the webarchive to the rename script in tchrist's post, so here is another one in Perl.

我认为链接已损坏,我在 tchrist 的帖子中找不到重命名脚本的 webarchive 页面,所以这里是 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/^(.+)~$/.#/'

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 $_;
}