Rename multiple files based on pattern in Unix

前端 未结 22 1237
死守一世寂寞
死守一世寂寞 2020-11-22 06:31

There are multiple files in a directory that begin with prefix fgh, for example:

fghfilea
fghfileb
fghfilec

I want to rename a

22条回答
  •  清歌不尽
    2020-11-22 07:02

    I would recommend using my own script, which solves this problem. It also has options to change the encoding of the file names, and to convert combining diacriticals to precomposed characters, a problem I always have when I copy files from my 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);
      }
    }
    

提交回复
热议问题