在一个目录中有多个以fgh开头的文件,例如:

fghfilea
fghfileb
fghfilec

我想将它们全部重命名为以前缀jkl开头。是否有一个单独的命令来执行该操作,而不是逐个重命名每个文件?


当前回答

这是find + sed + xargs解决方案的扩展版本。

原来的解是这个和这个。

要求:搜索,修剪,正则表达式,重命名

我想重命名多个文件夹中的多个文件。 一些文件夹应该被删除。 我在cygwin上,不能让perl重命名工作,这是最流行的解决方案所需要的(我假设它很慢,因为它似乎没有修剪选项?)

解决方案

使用find可以有效地获取文件(带有修剪),并提供许多自定义选项。 使用sed替换正则表达式。 使用xargs将结果汇集到最终命令中。

例1:重命名*.js文件,忽略node_modules

这个示例查找文件并对找到的文件和重命名的文件进行回显。出于安全考虑,它目前没有移动任何东西。你需要用mv代替echo。

set -x # stop on error
set -e # verbose mode (echo all commands)

find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js" | 
  sed -nE "s/(.*)\/my(.*)/& \1\/YOUR\2/p" |
  xargs -n 2 echo  # echo first (replace with `mv` later)

上面的脚本转换为:

./x/y/my-abc.js

到这个:

./x/y/YOUR-abc.js

溶液分解

find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js" Searches for files (-type f). The -not part excludes (and, importantly does not traverse!) the (notoriously ginormous) node_modules folder. File name must match "*.js". You can add more include and exclude clauses. Refs: This post discusses recursive file finding alternatives. This post discusses aspects of pruning and excluding. man find sed -nE "s/(.*)\/my\-(.*\.js)/& \1\/YOUR-\2/p" NOTE: sed always takes some getting used to. -E enables "extended" (i.e. more modern) regex syntax. -n is used in combination with the trailing /p flag: -n hides all results, while /p will print only matching results. This way, we only see/move files that need changing, and ignore all others. Replacement regex with sed (and other regex tools) is always of the format: s/regex/replacement/FLAGS In replacement, the & represents the matched input string. This will be the first argument to mv. Refs: linux regex tutorial man sed xargs -n 2 echo Run the command echo with (the first two strings of) the replaced string. Refs: man xargs

好运!

其他回答

有几种方法,但使用rename可能是最简单的。

使用一个版本的rename (Perl的rename):

rename 's/^fgh/jkl/' fgh*

使用另一个版本的rename(与Judy2K的答案相同):

rename fgh jkl fgh*

您应该检查您的平台的手册页,以确定上述哪一种方法适用。

安装Perl重命名脚本:

sudo cpan install File::Rename

在Stephan202的回答的评论中提到了两个重命名。 基于Debian的发行版有Perl的重命名。Redhat/rpm发行版的重命名为C。 OS X默认没有安装(至少在10.8中),Windows/Cygwin也没有。

我建议使用我自己的脚本,它可以解决这个问题。它还有更改文件名编码的选项,以及将组合符号转换为预组合字符的选项,这是我从Mac上复制文件时经常遇到的问题。

#!/usr/bin/perl

# Copyright (c) 2014 André von Kugland

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

$help_msg =
"rename.pl, a script to rename files in batches, using Perl
           expressions to transform their names.
Usage:
    rename.pl [options] FILE1 [FILE2 ...]
Where options can be:
    -v                      Verbose.
    -vv                     Very verbose.
    --apply                 Really apply modifications.
    -e PERLCODE             Execute PERLCODE. (e.g. 's/a/b/g')
    --from-charset=CS       Source charset. (e.g. \"iso-8859-1\")
    --to-charset=CS         Destination charset. (e.g. \"utf-8\")
    --unicode-normalize=NF  Unicode normalization form. (e.g. \"KD\")
    --basename              Modifies only the last element of the path.
";

use Encode;
use Getopt::Long;
use Unicode::Normalize 'normalize';
use File::Basename;
use I18N::Langinfo qw(langinfo CODESET);

Getopt::Long::Configure ("bundling");

# ----------------------------------------------------------------------------------------------- #
#                                           Our variables.                                        #
# ----------------------------------------------------------------------------------------------- #

my $apply = 0;
my $verbose = 0;
my $help = 0;
my $debug = 0;
my $basename = 0;
my $unicode_normalize = "";
my @scripts;
my $from_charset = "";
my $to_charset = "";
my $codeset = "";

# ----------------------------------------------------------------------------------------------- #
#                                        Get cmdline options.                                     #
# ----------------------------------------------------------------------------------------------- #

$result = GetOptions ("apply" => \$apply,
                      "verbose|v+" => \$verbose,
                      "execute|e=s" => \@scripts,
                      "from-charset=s" => \$from_charset,
                      "to-charset=s" => \$to_charset,
                      "unicode-normalize=s" => \$unicode_normalize,
                      "basename" => \$basename,
                      "help|h|?" => \$help,
                      "debug" => \$debug);

# If not going to apply, then be verbose.
if (!$apply && $verbose == 0) {
  $verbose = 1;
}

if ((($#scripts == -1)
  && (($from_charset eq "") || ($to_charset eq ""))
  && $unicode_normalize eq "")
  || ($#ARGV == -1) || ($help)) {
  print $help_msg;
  exit(0);
}

if (($to_charset ne "" && $from_charset eq "")
  ||($from_charset eq "" && $to_charset ne "")
  ||($to_charset eq "" && $from_charset eq "" && $unicode_normalize ne "")) {
  $codeset = langinfo(CODESET);
  $to_charset = $codeset if $from_charset ne "" && $to_charset eq "";
  $from_charset = $codeset if $from_charset eq "" && $to_charset ne "";
}

# ----------------------------------------------------------------------------------------------- #
#         Composes the filter function using the @scripts array and possibly other options.       #
# ----------------------------------------------------------------------------------------------- #

$f = "sub filterfunc() {\n    my \$s = shift;\n";
$f .= "    my \$d = dirname(\$s);\n    my \$s = basename(\$s);\n" if ($basename != 0);
$f .= "    for (\$s) {\n";
$f .= "        $_;\n" foreach (@scripts);   # Get scripts from '-e' opt. #
# Handle charset translation and normalization.
if (($from_charset ne "") && ($to_charset ne "")) {
  if ($unicode_normalize eq "") {
    $f .= "        \$_ = encode(\"$to_charset\", decode(\"$from_charset\", \$_));\n";
  } else {
    $f .= "        \$_ = encode(\"$to_charset\", normalize(\"$unicode_normalize\", decode(\"$from_charset\", \$_)));\n"
  }
} elsif (($from_charset ne "") || ($to_charset ne "")) {
    die "You can't use `from-charset' nor `to-charset' alone";
} elsif ($unicode_normalize ne "") {
  $f .= "        \$_ = encode(\"$codeset\", normalize(\"$unicode_normalize\", decode(\"$codeset\", \$_)));\n"
}
$f .= "    }\n";
$f .= "    \$s = \$d . '/' . \$s;\n" if ($basename != 0);
$f .= "    return \$s;\n}\n";
print "Generated function:\n\n$f" if ($debug);

# ----------------------------------------------------------------------------------------------- #
#                 Evaluates the filter function body, so to define it in our scope.               #
# ----------------------------------------------------------------------------------------------- #

eval $f;

# ----------------------------------------------------------------------------------------------- #
#                  Main loop, which passes names through filters and renames files.               #
# ----------------------------------------------------------------------------------------------- #

foreach (@ARGV) {
  $old_name = $_;
  $new_name = filterfunc($_);

  if ($old_name ne $new_name) {
    if (!$apply or (rename $old_name, $new_name)) {
      print "`$old_name' => `$new_name'\n" if ($verbose);
    } else {
      print "Cannot rename `$old_name' to `$new_name'.\n";
    }
  } else {
    print "`$old_name' unchanged.\n" if ($verbose > 1);
  }
}

使用重命名:

$ renamer --find /^fgh/ --replace jkl * --dry-run

一旦您对输出看起来正确感到满意,就删除——dry-run标志。

rename fgh jkl fgh*