Move characters from the start of filenames to the end (before extension) and add whitespace

I have ~2000 files in an original naming scheme.

I need to take them all, move the first 4 characters to the end of the filename before the extension, and then add a whitespace before the first 4 characters.

Basically, from:

0123 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).jpg

to

[UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL) 0123.jpg

Solution 1:

This should work:

rename -n 's/^([0-9]+) (.*)\.jpg/$2 $1.jpg/' /path/to/files/*.jpg

Sample:

0324 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt
0123 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt
0124 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt

Results:

rename(0123 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt,  [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL) 0123.txt)
rename(0124 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt,  [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL) 0124.txt)
rename(0324 [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL).txt,  [UNKNOWN] (Final Fantasy 9) headshot of Freya Crescent {sketch} (ORIGINAL) 0324.txt)

Note: Tested with .txt files will also work on jpg filenames

Information:

([0-9]+): pick the numbers at the front.

(.*): pick every other thing till the file extension.

$2 $1.txt: return the captured groups with the returned group for numbers placed close to the file extension jpg and add a space before the numbers.

-n: run without changing filename so we see what files are changed and what the names are changed to, remove this to rename the files.

Solution 2:

Use find and Shell Parameter Expansion:

  1. If you don't have rename installed (but most probably it's already installed as part of Perl packages).
  2. You can perform on all or specified matched file patterns "*.jpg" only.
  3. It's recursively as find nature is.
find . -type f -execdir \
    sh -c 'X="[${1#*[}"; Y="${1%% *}"; 
    echo mv -v "$1" "${X%.*} ${Y#./}.${X##*.}"' find-sh '{}' \;

Explanations:

  • X="[${1#*[}" (cut-up-to-first-prefix): This removes everything until first [ seen, and appends [ back to the pattern.

  • Y="${1%% *}" (cut-up-to-last-suffix): This removes everything until last space seen starts from end to the beginning of the filename; This will result ./PATTERN which is ./0123 as example.

  • ${X%.*} (cut-up-to-first-suffix): This removes suffix (ex: .jpg).

  • Y="${Y#./}" (cut-up-to-first-prefix): This removes ./ from variable Y and will result PATTERN only from second step which is 0123 now.

  • .${X##*.}" (cut-up-to-last-prefix): This removes everything until last dot . seen starts from beginning to the end of the filename and append back a dot .; This will result .PATTERN which is .jpg now.

  • -execdir used here to don't result file path by find command and it's safe to intact the /path/to/files/. This will produce a prompt if you have current directory in your PATH or if it contains relative paths which is unsafe.

  • echo is used for dry run, remove it to have actual rename.