bash - Move numbers in a filename to the start

07
2014-07
  • handuel

    I have several files in a folder, with names in the form: SOMETEXT1 number SOMETEXT2.mp3, or SOMETEXT number.mp3. I want to rename these to number SOMETEXT SOMETEXT2.mp3, or number SOMETEXT.mp3. Using bash and common GNU command line tools, how would I achieve this?

  • Answers
  • grawity

    Using perl-rename (sometimes called prename):

    prename -v 's/^(.+) (\d+)( .+|\.[^.]+)$/\2 \1\3/' *
    

    Use -n to just test without renaming.

    The same with bash:

    re='^(.+) ([0-9]+)( .+|\.[^.]+)$'
    for file in *; do
        new=$file
        if [[ "$file" =~ $re ]]; then
            new="${BASH_REMATCH[2]} ${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
        fi
        if [[ "$new" != "$file" ]]; then
            mv -v "$file" "$new"
        fi
    done
    

  • Related Question

    bash - Rename sets of files based on size
  • Dave Jarvis

    Background

    Rename one set of files based on a name that corresponds to another set, using a sort order based on file size to match the file names. The files from both sets have approximately the same sizes. Close enough that when sorted by file size both lists are in the same order. The number of files in each set is exactly the same.

    Problem

    First file set:

    master~$ for f in $(ls -S); do echo $f; done
    06-AudioTrack_06.flac
    08-AudioTrack_08.flac
    01-AudioTrack_01.flac
    05-AudioTrack_05.flac
    02-AudioTrack_02.flac
    

    Second file set:

    corrupt~$ for f in $(ls -S); do echo $f; done
    Groove_de_V..flac
    Jump.flac
    Do_You_Savvy.flac
    Gershwins_Blues.flac
    Blue_Skies.flac
    If_I_Had_A_Ribbon_Bow.flac
    

    Question

    How do you rename the first set as follows:

    06-Groove_de_V..flac
    08-Jump.flac
    01-Do_You_Savvy.flac
    05-Gershwins_Blues.flac
    02-Blue_Skies.flac
    

    Script

    So far...

    master~$ for f in $(ls -S); do
      IDX=$(echo $f | awk '{print substr( $1, 1, 2 )}');
      echo "mv $i $IDX-";
    done
    

    Produces:

    mv 06-AudioTrack_06.flac 06-
    mv 08-AudioTrack_08.flac 08-
    mv 01-AudioTrack_01.flac 01-
    mv 05-AudioTrack_05.flac 05-
    mv 02-AudioTrack_02.flac 02-
    

    Thank you!


  • Related Answers
  • Dennis Williamson

    Some modifications to your script eliminating the need for AWK and simplifying the incrementing of the index variable. It will also now correctly handle filenames that include spaces.

    #!/bin/bash
    
    index=0
    
    # Store the names of original (corrupt) files
    while read -r f
    do
        corrupt[index++]=${f##*/}
    done < <(ls -S "$1"/*.flac)
    
    index=0
    
    while read -r f
    do
        idx=${f:0:2}
        original=${corrupt[index++]}
        echo mv "$f" "$idx-$original"
    done < <(ls -S *.flac)
    
  • Dave Jarvis
    #!/bin/bash
    
    let INDEX=0
    
    # Store the names of original (corrupt) files
    for f in $(ls -S "$1"/*.flac); do
      corrupt[$INDEX]=$(basename "$f");
      let INDEX="$INDEX+1"
    done
    
    let INDEX=0
    
    for f in $(ls -S *.flac); do
      IDX=$(echo $f | awk '{ print substr( $1, 1, 2 ) }');
      original=${corrupt[$INDEX]};
    
      echo "mv $f $IDX-$original";
    
      let INDEX="$INDEX+1"
    done