6

Problem

I have thousands folders, which names are structured like:
firstName_lastName_date
for which I want to swap the two first parts using the underscore _ as a separator in order to end up with:
lastName_firstName_date

Warning

lastName may be be preceded by a nobiliary particle, separated with an extra _ in the input folders.
For example:
firstName_de_lastName_date
firstName_von_lastName_date

For which the wanted output should be:
de_lastName_firstName_date
von_lastName_firstName_date

Information

  • date is always the last element.
  • First names are single words.
  • Last names are single words or composed words (2) with a particle.

Tools

I want to do that using rename in bash, preferably, or shell Parameter expansion.

References

https://www.gnu.org/software/sed/manual/html_node/Regular-Expressions.html

1
  • Can a last name have multiple parts in addition to the particle? Or a first name? Can you have something like Jose_Maria_de_los_lobos_y_garcia_date? Or can we be sure there will always be either 3 or 2 _ and whatever is between the 1st and last _ will be the last name?
    – terdon
    Jan 19, 2020 at 13:29

1 Answer 1

9

You can do it using the Perl-based rename I think, using a mix of non-greedy and greedy matches ex.

$ rename -n 's/^(.*?)_(.*)_(.*?)$/$2_$1_$3/' *
rename(firstName_de_lastName_date, de_lastName_firstName_date)
rename(firstName_lastName_date, lastName_firstName_date)
rename(firstName_von_lastName_date, von_lastName_firstName_date)

The non-greedy modifier on the last (date) group isn't really necessary - but I like the symmetry.

Alternatively, with the shell alone

$ for f in *; do 
    m="${f#*_}"; m="${m%_*}"; echo mv -- "$f" "${m}_${f%%_*}_${f##*_}";
  done
mv -- firstName_de_lastName_date de_lastName_firstName_date
mv -- firstName_lastName_date lastName_firstName_date
mv -- firstName_von_lastName_date von_lastName_firstName_date

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .