开发者

Renaming lots of files in Linux according to a pattern [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers. 开发者_JAVA百科

Closed 8 years ago.

  • This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
  • This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Improve this question

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.

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

2) Files containing _ should be -

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]


There's a rename command provided with most Debian/Ubuntu based distros which was written by Robin Barker based on Larry Wall's original code from around 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/' *

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

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 renameutils package with these tools.

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.


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

  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
    

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.


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

% rename 's/_/-/g' *
% rename 's/(\p{Lower})(\p{Upper})/$1 $2/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:

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.

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


The above answers apply to Debian, Ubuntu etc

For RHEL and co: rename from_pattern to_pattern files


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.

#!/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 $_;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜