Rename multiple files in Unix

2018-12-31 15:22发布

问题:

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

fghfilea
fghfileb
fghfilec

I want to rename all of them to begin with prefix jkl. Is there a single command to do that instead of renaming each file individually?

回答1:

There are several ways, but using rename will probably be the easiest.

Using one version of rename:

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

Using another version of rename (same as Judy2K\'s answer):

rename fgh jkl fgh*

You should check your platform\'s man page to see which of the above applies.



回答2:

This is how sed and mv can be used together to do rename:

for f in fgh*; do mv \"$f\" $(echo \"$f\" | sed \'s/^fgh/jkl/g\'); done

As per comment below, if the file names have spaces in them, quotes may need to surround the sub-function that returns the name to move the files to:

for f in fgh*; do mv \"$f\" \"$(echo $f | sed \'s/^fgh/jkl/g\')\"; done


回答3:

rename might not be in every system. so if you don\'t have it, use the shell this example in bash shell

for f in fgh*; do mv \"$f\" \"${f/fgh/xxx}\";done


回答4:

Using mmv:

mmv \"fgh*\" \"jkl#1\"


回答5:

There are many ways to do it (not all of these will work on all unixy systems):

  • ls | cut -c4- | xargs -I§ mv fgh§ jkl§

    The § may be replaced by anything you find convenient. You could do this with find -exec too but that behaves subtly different on many systems, so I usually avoid that

  • for f in fgh*; do mv \"$f\" \"${f/fgh/jkl}\";done

    Crude but effective as they say

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

    Real pretty, but rename is not present on BSD, which is the most common unix system afaik.

  • rename fgh jkl fgh*

  • ls | perl -ne \'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_\';

    If you insist on using Perl, but there is no rename on your system, you can use this monster.

Some of those are a bit convoluted and the list is far from complete, but you will find what you want here for pretty much all unix systems.



回答6:

rename fgh jkl fgh*


回答7:

Using find, xargs and sed:

find . -name \"fgh*\" -type f -print0 | xargs -0 -I {} sh -c \'mv \"{}\" \"$(dirname \"{}\")/`echo $(basename \"{}\") | sed \'s/^fgh/jkl/g\'`\"\'

It\'s more complex than @nik\'s solution but it allows to rename files recursively. For instance, the structure,

.
├── fghdir
│   ├── fdhfilea
│   └── fghfilea
├── fghfile\\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
    ├── fghfile\\ e
    ├── fghfilea
    ├── fghfileb
    └── fghfilec

would be transformed to this,

.
├── fghdir
│   ├── fdhfilea
│   └── jklfilea
├── jklfile\\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
    ├── jklfile\\ e
    ├── jklfilea
    ├── jklfileb
    └── jklfilec

The key to make it work with xargs is to invoke the shell from xargs.



回答8:

To install the Perl rename script:

sudo cpan install File::Rename

There are two renames as mentioned in the comments in Stephan202\'s answer. Debian based distros have the Perl rename. Redhat/rpm distros have the C rename.
OS X doesn\'t have one installed by default (at least in 10.8), neither does Windows/Cygwin.



回答9:

On Solaris you can try:

for file in `find ./ -name \"*TextForRename*\"`; do 
    mv -f \"$file\" \"${file/TextForRename/NewText}\"
done


回答10:

#!/bin/sh

#replace all files ended witn .f77 to .f90 in a directory

for filename in *.f77
do 
    #echo $filename
    #b= echo $filename | cut -d. -f1
    #echo $b    
    mv \"${filename}\" \"${filename%.f77}.f90\"    
done


回答11:

Here\'s a way to do it using command-line Groovy:

groovy -e \'new File(\".\").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst(\"fgh\", \"jkl\"))}\'


回答12:

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.

https://github.com/kugland/rename.pl/blob/master/rename.pl



回答13:

Using StringSolver tools (windows & Linux bash) which process by examples:

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea

It first computes a filter based on examples, where the input is the file names and the output (ok and notok, arbitrary strings). If filter had the option --auto or was invoked alone after this command, it would create a folder ok and a folder notok and push files respectively to them.

Then using the filter, the mv command is a semi-automatic move which becomes automatic with the modifier --auto. Using the previous filter thanks to --filter, it finds a mapping from fghfilea to jklfilea and then applies it on all filtered files.


Other one-line solutions

Other equivalent ways of doing the same (each line is equivalent), so you can choose your favorite way of doing it.

filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea \"mv fghfilea jklfilea\"
# Even better, automatically infers the file name
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter \"mv fghfilea jklfilea\"

Multi-step solution

To carefully find if the commands are performing well, you can type the following:

filter fghfilea ok
filter fghfileb ok
filter fghfileb notok

and when you are confident that the filter is good, perform the first move:

mv fghfilea jklfilea

If you want to test, and use the previous filter, type:

mv --test --filter

If the transformation is not what you wanted (e.g. even with mv --explain you see that something is wrong), you can type mv --clear to restart moving files, or add more examples mv input1 input2 where input1 and input2 are other examples

When you are confident, just type

mv --filter

and voilà! All the renaming is done using the filter.

DISCLAIMER: I am a co-author of this work made for academic purposes. There might also be a bash-producing feature soon.



回答14:

It was much easier (on my Mac) to do this in Ruby. Here are 2 examples:

# for your fgh example. renames all files from \"fgh...\" to \"jkl...\"
files = Dir[\'fgh*\']

files.each do |f|
  f2 = f.gsub(\'fgh\', \'jkl\')
  system(\"mv #{f} #{f2}\")
end

# renames all files in directory from \"021roman.rb\" to \"021_roman.rb\"
files = Dir[\'*rb\'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}

files.each do |f|
  f1 = f.clone
  f2 = f.insert(3, \'_\')
  system(\"mv #{f1} #{f2}\")
end


回答15:

Using renamer:

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

Remove the --dry-run flag once you\'re happy the output looks correct.



回答16:

My version of renaming mass files:

for i in *; do
    echo \"mv $i $i\"
done |
sed -e \"s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh


回答17:

This worked for me using regexp:

I wanted files to be renamed like this:

file0001.txt -> 1.txt
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt

usig the [a-z|_]+0*([0-9]+.) regexp where ([0-9]+.) is a group substring to use on the rename command

ls -1 | awk \'match($0, /[a-z|\\_]+0*([0-9]+.*)/, arr) { print   arr[0]  \" \"  arr[1] }\'|xargs  -l mv

Produces:

mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt

Another example:

file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk \'match($0, /[a-z|\\_]+0*([0-9]+.*)([a-z]+)/, arr) { print   arr[0]  \" \"  arr[2] arr[1] }\'|xargs  -l mv

Produces:

  mv file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 

Warning, be careful.



回答18:

I wrote this script to search for all .mkv files recursively renaming found files to .avi. You can customize it to your neeeds. I\'ve added some other things such as getting file directory, extension, file name from a file path just incase you need to refer to something in the future.

find . -type f -name \"*.mkv\" | while read fp; do 
fd=$(dirname \"${fp}\");
fn=$(basename \"${fp}\");
ext=\"${fn##*.}\";
f=\"${fn%.*}\";
new_fp=\"${fd}/${f}.avi\"
mv -v \"$fp\" \"$new_fp\" 
done;


回答19:

A generic script to run a sed expression on a list of files (combines the sed solution with the rename solution):

#!/bin/sh

e=$1
shift

for f in $*; do
    fNew=$(echo \"$f\" | sed \"$e\")
    mv \"$f\" \"$fNew\";
done

Invoke by passing the script a sed expression, and then any list of files, just like a version of rename:

script.sh \'s/^fgh/jkl/\' fgh*


回答20:

You can also use below script. it is very easy to run on terminal...

//Rename multiple files at a time

for file in  FILE_NAME*
do
    mv -i \"${file}\" \"${file/FILE_NAME/RENAMED_FILE_NAME}\"
done

Example:-

for file in  hello*
do
    mv -i \"${file}\" \"${file/hello/JAISHREE}\"
done