van
van

Reputation: 9449

Batch rename files

I want to batch re-name a number of files in a directory so that the preceding number and hypen are stripped from the file name.

Old file name: 2904495-XXX_01_xxxx_20130730235001_00000000.NEW
New file name:         XXX_01_xxxx_20130730235001_00000000.NEW

How can I do this with a linux command?

Upvotes: 25

Views: 50147

Answers (9)

Lloyd
Lloyd

Reputation: 8396

Using renamer (Windows, Mac and Linux friendly):

$ renamer --find '/\d+-(.*)/' --replace '$1' *

This will strip all numbers and first hyphen from the start of all files in the current directory.

Upvotes: 3

thameera
thameera

Reputation: 9473

vimv lets you rename multiple files using Vim's text editing capabilities.

Entering vimv opens a Vim window which lists down all files and you can do pattern matching, visual select, etc to edit the names. After you exit Vim, the files will be renamed.

The screencast in the README file shows how it solves original poster's question.

[Disclaimer: I'm the author of the tool]

Upvotes: 1

Peter T.
Peter T.

Reputation: 3315

There is also a handy GUI tool pyRenamer https://wiki.ubuntuusers.de/pyRenamer/

Upvotes: 1

Joyer
Joyer

Reputation: 431

I really like something as "rename *.mp3 *.mp4".

But none of other answers give me that. So I wrote a haskell program to do it.

https://hackage.haskell.org/package/batch-rename

With this you can do: batch_rename "DCIM*.jpg" "*.png"

Upvotes: 0

doms
doms

Reputation: 221

I think this command would better if you execute the command below:

ls * | sed -e 'p;s/old-name/new-name/' | xargs -n2 mv

Here
ls * - lists files in curent folder
sed -e - executes expression
p; - prints old file name
s/old-name/new-name/ - produce new filename
xargs -n2 - handles two arguments to mv
mv - gets two parameters and do move operation

Recommendation: before executing mv verify what you do is what you want to achieve with echo.

ls * | sed -e 'p;s/old-name/new-name/' | xargs -n2 echo

Following example renames

SCCF099_FG.gz5329223404623884757.tmp to
SCCF099_FG.gz

ls *tmp | sed -e 'p;s/\([0-9]\)\+\.tmp/ /g' | xargs -n2 echo
ls *tmp | sed -e 'p;s/\([0-9]\)\+\.tmp/ /g' | xargs -n2 mv

Upvotes: 22

fedorqui
fedorqui

Reputation: 289505

This should make it:

rename 's/^[0-9]*-//;' *

It gets from the beginning the block [0-9] (that is, numbers) many times, then the hyphen - and deletes it from the file name.


If rename is not in your machine, you can use a loop and mv:

mv "$f" "${f#[0-9]*-}"

Test

$ ls
23-aa  hello aaa23-aa
$ rename 's/^[0-9]*-//;' *
$ ls
aa  hello aaa23-aa

Or:

$ ls
23-a  aa23-a  hello
$ for f in *;
> do
>   mv "$f" "${f#[0-9]*-}"
> done
$ ls
a  aa23-a  hello

Upvotes: 42

Jahid
Jahid

Reputation: 22428

You can use this tool: rnm

Code to do what you want:

rnm /path/to/the/directory -fo -dp -1 -rs '/^\d+-//' -ss '^\d+-'

-fo is for file only mode
-dp is the depth of directory ( -1 means unlimited depth).
-rs is replace string. \d+- regex is being replaced with empty string.
-ss is search string, it searches for files with ^\d+- regex. (It could be omitted though, some harmless error messages would be printed on screen).

Upvotes: 0

jerdiggity
jerdiggity

Reputation: 3665

This might look a little complex, but it's pretty effective and works well on both *nix and OSX systems. It also acts recursively, renaming files in the current directory as well as any subdirectories:

find . -regex '.*/[0-9]\{7\}[-].*' -print > temp1 && \
cp temp1 temp2 && \
vi -c ":g/\([0-9]\{7\}[-]\)\(.*\)/s//\2/" -c ":x" temp2 && \
paste temp1 temp2 > temp3 && \
vi -c ":g/^/s//mv /" -c ":x" temp3 && \
sh ./temp3 && \
rm temp1 temp2 temp3

Here's a breakdown of what just happened:

The first line says to find (find) all files, starting with those in the current directory (.), whose name matches the pattern (-regex) of "7 numbers, followed by a dash, followed by 0 or more characters" ('.*/[0-9]\{7\}[-].*'), and write those file names and their respective paths (-print) to a file called temp1 (> temp1). Note that the -print directive is probably not necessary in most cases but it shouldn't hurt anything.

find . -regex '.*/[0-9]\{7\}[-].*' -print > temp1 && \

Then, copy (cp) the contents of temp1 to a file called temp2.

cp temp1 temp2 && \

Next, open the file temp2 using the vi text editor and give vi two commands (using -c to signify each new command):

  1. Command #1:
    • Search each line of temp2 (:g) for the same pattern we searched for above, except this time group the results using parentheses (\([0-9]\{7\}[-]\)\(.*\)).
    • For each matching line, move the cursor to where the match was found and replace the whole match with only the second group of the matched pattern (\2).
  2. Command #2:
    • Save the changes made to temp2 and close the file (:x).

The result of which being this:

 vi -c ":g/\([0-9]\{7\}[-]\)\(.*\)/s//\2/" -c ":x" temp2 && \

Now, concatenate the lines from temp1 with those of temp2 (paste) and write each newly combined line to a file called temp3 (> temp3).

paste temp1 temp2 > temp3 && \

Next, run vi again, doing the same steps as above except this time search for the beginning of each line (^) inside the file temp3 and add mv and one space right after it (mv).

vi -c ":g/^/s//mv /" -c ":x" temp3 && \

Then, execute the contents of temp3 (./temp3) as a shell script (sh).

sh ./temp3 && \

Finally, remove (rm) each of the temporary files we created during the whole process.

rm temp1 temp2 temp3

Upvotes: 2

David Souther
David Souther

Reputation: 8174

If the first numbers are always the same length:

for F in *new ; do
    mv $F ${F:8}
done

The ${parameter:number} does a substring expansion - takes the string starting at the 8th character.

There are many other string edits available in expansions to handle other cases.

Upvotes: 7

Related Questions