rename folder by changing the order

I have several directories with names like:

"Some NameAndMorEyy_mm_dd"

and I want to rename them like:

"yy_mm_dd_Some NameAndMore"

Where, the Some NameAndMore part can contain accent marks, spaces, and can end with space or _ or both, and those need to be removed.

Some examples:

"Jhon Doe_18_08_02"
"Jhon Doe 18_08_03"
"Jhon Doe_ 18_08_04"
"Jhon Doe _18_07_02"
"Jhon Doé_18_10_02"
"Jhon Doñe_18_08_02"

Should be renamed to:

"18_08_02_Jhon Doe"
"18_08_03_Jhon Doe"
"18_08_04_Jhon Doe"
"18_07_02_Jhon Doe"
"18_10_02_Jhon Doé"
"18_08_02_Jhon Doñe"


Now, the ones ending with both and space and _ are just a few, so you can ignore them if you want.


3 Answers rename folder by changing the order

Here is a somewhat slow solution, but it should work. Replace the echo "move ..." with an actual move command. It could be sped up with using fewer subshells to sed.

The idea is to find the split by finding the start of the numbers. This assumes the names do not have any numbers in them. We break into the two parts, and remove any _ or spaces from the name, and then combine back together in the move.

Also uses find so that the files with spaces can be properly handled.


find . -mindepth 1 -maxdepth 1 -type d | (while read -r d; do
  d=$(basename "$d")
  name_part=$(echo "$d" | sed -rn 's/(^[^0-9]+)(.*)$/\1/p')
  date_part=$(echo "$d" | sed -rn 's/(^[^0-9]+)(.*)$/\2/p')

  name_part=$(echo "$name_part" | sed -rn 's/([_ ]+)$//p')

  # change this line here
  # mv "$d" "${date_part}_${name_part}"
  echo "move $d ==> ${date_part}_${name_part}"

From the test data, the output shows:

move Jhon Doe_18_08_02 ==> 18_08_02_Jhon Doe
move Jhon Doe 18_08_03 ==> 18_08_03_Jhon Doe
move Jhon Doe_ 18_08_04 ==> 18_08_04_Jhon Doe
move Jhon Doñe_18_08_02 ==> 18_08_02_Jhon Doñe
move Jhon Doé_18_10_02 ==> 18_10_02_Jhon Doé

4 months ago

And a lazy one liner :) ... strip the first echo to make it work.

for i in *; do  [[ -d $i ]] && echo mv "$i" "$( echo $i| sed -r -e 's/^(.+)([0-9][0-9]_[0-9][0-9]_[0-9][0-9])$/\2_\1/' -e 's/[_ ]+$//' )" ; done
mv Jhon Doe _18_07_02 18_07_02_Jhon Doe
mv Jhon Doe_18_08_02 18_08_02_Jhon Doe
mv Jhon Doe 18_08_03 18_08_03_Jhon Doe
mv Jhon Doe_ 18_08_04 18_08_04_Jhon Doe
mv Jhon Doé_18_10_02 18_10_02_Jhon Doé
mv Jhon Doñe_18_08_02 18_08_02_Jhon Doñ

4 months ago

This (except for the mv) is a pure Bash solution:

#! /bin/bash

shopt -s dotglob    # Globs match names beginning with '.'
shopt -s nullglob   # Globs expand to nothing when nothing matches

for namedate in *[0-9][0-9]_[0-9][0-9]_[0-9][0-9] ; do
    [[ -d $namedate ]] || continue  # Skip non-directories
    name=${namedate%??_??_??}       # Remove date from end to get name
    date=${namedate#"$name"}        # Remove name from start to get date
    name=${name%[ _]}               # Remove trailing space or _
    name=${name%[ _]}               # Remove possible 2nd trailing space or _

    if [[ -e $datename ]] ; then
        printf "Warning: '%s' already exists.  Skipping.\\n" "$datename" >&2
        mv -- "$namedate" "$datename"
        printf "Moved '%s' to '%s'\\n" "$namedate" "$datename" >&2

The code is Shellcheck-clean. To avoid doing something strange, it checks that the destination directory doesn't exist before doing the mv.

4 months ago