4

I have to rename a set of files, using the rename command (with a regular expression).  After some tries, I'm not able to find an expression that gets the expected result.

I've got a file pattern like that:

prefix_some_name_other.txt

All files begin with the "prefix_" string and end with "_other.txt", and the some_name part can consist of multiple (alphanumeric) words separated by underscores.  So it's possible to have:

prefix_one_name_other.txt
prefix_this_is_my_name_1_this1_other.txt

I need to rename the filenames like these:

other_one-name_datetime
other_this-is-my-name-1-this1_datetime

In other words:

  • Need to delete "prefix" (leaving the underscore)
  • "other" token goes to the beginning of the file name
  • In some_name, convert underscore (_) to dash (-)
  • The underscore at the end of the filename (after some_name) must remain
  • Need to delete the .txt extension, replaced by datetime.

What I've tried:

rename 's/fw_([a-z]+)_(\d)_(\w+\d)_(\w+)\.txt/$4_$1-$2-$3_'$datahora'/' *.txt

$datahora has datetime value (tested). This works as expected with

prefix_name_1_gnt1_other.txt

but not with

prefix_other_name_2_gnt2_other.txt

Where did I go wrong? How else could I accomplish that?

I have hanged my mind, since for now I'm not able to find a regex that works for all file names that I've got. I know, that the first element in the string is always the prefix part, and the last element is then other.txt part of the string. So is possible to split string into an array, and get the items that I need to build the new name. In fact, something like that.

datahora="20140718-080000"
arrfiles=( *.txt )
for curfile in ${arrfiles[*]}
do
    arrparts=( ${curfile//_/ } )
    numitems=${#arrparts[*]}
    newname=""
    for (( c=1; c<numitems-1; c++ ))
    do
        newname+="${arrparts[c]}-"
    done
    newname=${newname%-}
    arrparts[numitems-1]=${arrparts[numitems-1]/.txt/}
    newname="${arrparts[numitems-1]}_${newname}_$datahora"
    echo "$curfile pasa a $newname"
    mv ${curfile} ${newname}
done

After done in this way, I have give another try to @peterph suggestion, and finally done with some rename regex combinations. Somethink like that:

rename 's/_/-/g' *.txt
rename 's/^fw-(.*)-([^-]*)(\.txt)/$2.$1$3/' *.txt
rename 's/(\w+)\.(.*)(\.txt)/$1_$2_'$datahora'/' *.txt

I'm not sure what is the best aproach. In my opinion, the regex variant seems more elegant, but I need three rename operations (access three times to disk) to do the work, while the arrayvariant only writes once onto disk.

¿What do you think about those two solutions?...

Thank's again.

  • Might be better suited for the Unix & Linux SE. – peterph Jul 17 '14 at 20:41
  • May I move this question? – Ferran Jul 17 '14 at 23:36
2

Unless your rename can accept multiple substitution commands and the root of the file name (some_name) may contain more than one underscore, you have to do this in two steps: a) replacing underscores with dashes and b) (re)moving chunks around in the file names.

The regular expressions you are looking for can be for example:

rename 's/_/-/g' *.txt
rename 's/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt

The first one does the underscore to dash translations while the latter does the swapping of root and suffix and appends the contents of the DATETIME environment variable to the names. And omits the prefix and extension, of course.

The [^-]* part matches any string not containing a dash. In case the suffix is always the same you can put it there verbatim as is the case with the prefix (and vice versa - if the prefix may vary, use ^[^-]*- to match it as any string not containing a dash located between the beginning of the file name and (thus) the first dash).

If your rename supports multiple commands, just concatenate them:

rename 's/_/-/g;s/^prefix-(.*)-([^-]*).txt$/$2_$1_'$DATETIME'/' *txt
  • Thank you very mucho peter, but seem's it doesn't work as spected. I get this conversion: other-this-is-1-name-20140717-093458 When I'm looking for: other_this-is-1-name_20140717-093458 Note the underscore after otherand before datetime. – Ferran Jul 17 '14 at 23:18
  • With a little changes into the regex @peterph suggest, and combine with other regex to make the work. See my new edit for further details. – Ferran Jul 18 '14 at 7:31
  • Sorry, I didn't read the question carefully enough - I've updated the answer. You just need to change the separators around the file name root: just replace the dashes around $2 with underscores in the second regexp. – peterph Jul 18 '14 at 21:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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