Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have several thousand files of the form:

[8-digit number]_[number I want]_S60491_I129111.dcm.

I wish to remove everything except the number I want, and use that as its name. In Ruby, I can get to that value with the regular expression /^.*_(\d+)_S60491_I12911.dcm/, but I'm having trouble trying to translate that to a sed expression that allows me to substitute the full filename for just that number between the underscores.

Is there a way using sed or other basic Bash commands to do what I want? If it helps, the number I want is just a counter (i.e. it runs from 1 to 2100), and the prefix 8-digit number happens to result in the files being listed in correct order (i.e. from file 1 to file 2100), so I may be over-thinking things.

share|improve this question

4 Answers 4

up vote 1 down vote accepted

This works for me: for a in * ; do mv "$a" $(echo "$a" | cut -d'_' -f 2) ; done

toad:/home/hennes/work/foo>ls -l
total 0
-rw-------  1   users  0 Jan 23 22:19 12345678_023454_S60491_I129111.dcm
-rw-------  1   users  0 Jan 23 22:19 12345678_123454_S60491_I129111.dcm
-rw-------  1   users  0 Jan 23 22:19 12345678_123456_S60491_I129111.dcm

toad:/home/hennes/work/foo>for a in * ; do mv $a $(echo $a | cut -d'_' -f 2) ; done

toad:/home/hennes/work/foo>ls -l
total 0
-rw-------  1   users  0 Jan 23 22:23 023454
-rw-------  1   users  0 Jan 23 22:23 123454
-rw-------  1   users  0 Jan 23 22:23 123456

for a in * selects all files. If there are more files a *.dcm can be used instead.

mv (move) changes the filename

from $a (the filename select in for)

to field2 of the name, with _ used a field delimiter.

Note that this script will move the files, so the old file names will be lost. You can use 'cp' rather than 'mv' to make a copy instead.

If you want to keep the extension then add it after the -f 2).
E.g. for a in * ; do cp $a $(echo $a | cut -d'_' -f 2).dcm ; done

share|improve this answer

There is a tool commonly named rename or prename installed on most systems. On my Debian/Ubuntu systems this comes as part of Perl. It allows you to use Perl style regular expressions to manipulate filenames however you like.

Your command would probably look like this. I do suggest you pass the --no-act option and examine the output before you actually commit to making any changes.

prename 's/^.*_(\d+)_S60491_I12911.dcm/$1/' *
share|improve this answer
    
I found rename and prename come up a bit when trying to search for a solution myself, but unfortunately it doesn't seem to be on the server at work I'm using for this (it looks like it's a version of Red Hat). Definitely something I'll look in to on my home computer though. –  ackrause Jan 23 '13 at 22:34
    
It is a pretty simple perl script. You could almost certainly snag a copy from some other box, if you have Perl installed. –  Zoredache Jan 23 '13 at 22:40

Since we know the format of the names and none contain spaces:

for a in * ; do
   mv $a $(echo $a | sed 's/[^_]*_//;s/_S60491_I129111.dcm//')
done
share|improve this answer
    
Sorry about the edit/rollback, I saw this would break on spaces but missed your disclaimer. –  terdon Jul 2 at 15:10

There are many ways to get this done. But since you asked for sed, this would do:

ls *dcm | sed 's/^([0-9]{8}_([0-9]*)_S60491_I129111.dcm)/mv \1 \2 /g' | bash

The first bit of the pattern selects 8-digit numbers, then you look for any digits (since you didn't mention what size the second number was) and then your trailing sequence. \1 and \2 refer to the contents of the outer and inner escaped parentheses \(...\). You can replace bash by any shell in this case.

The GNU extensions of sed would allow you to do also:

ls *dcm | sed 's/^([0-9]{8}_([0-9]+)_S60491_I129111.dcm)/mv \1 \2 /g' | bash

where + allows for matching one or more, where * matches zero or more, which causes problems for 12345678__S60491_I129111.dcm.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.