I want to change a string like author - name in some books' filenames to name - author. I'm trying

ls * | sed -r 's/(.+) - (.+).pdf/mv \2 - \1.pdf/' | sh

Maybe its a mix of Switch two arbitrary length strings separated by a symbol and Rename multiple files with sed

This doesn't work

for file in *; do mv "$file" "$(echo "$file" | sed -r 's/(.+) - (.+).pdf/\2 - \1.pdf/')"

Neither does

rename 's/\([.]+\) - \([.]+\)\.pdf/\2 - \1\.pdf/' *

This works

rename 's/(.+) - (.+).pdf/\2 - \1.pdf/' *

I'm assuming that the filenames follow the pattern author - name.pdf and that both author and name may contain any valid character apart from - surrounded by spaces.

find . -type f -name '* - *.pdf' \
    -execdir sh -c 'b=${1% - *}; e=${1#* - }; mv "$1" "${e%.pdf} - $b.pdf"' sh {} \;

This finds all regular files in the current directory that have names matching the pattern * - *.pdf.

For each such file, a subshell is executed. The subshell does the following:

b=${1% - *}  # pick out the start of the filename
e=${1#* - }  # pick out the end of the filename

# Combine $b and $e into a new filename while removing ".pdf" from
# the end of the original filename and adding it to the end of
# the new filename instead.
mv "$1" "${e%.pdf} - $b.pdf"

Testing it:

$ ls -l
total 0
-rw-r--r--  1 kk  wheel  0 Aug 30 11:31 arr! - Boaty McBoatface.pdf
-rw-r--r--  1 kk  wheel  0 Aug 30 11:30 hello world - bingo-night!.pdf

$ find . -type f -name '* - *.pdf' -execdir sh -c 'b=${1% - *}; e=${1#* - }; mv "$1" "${e%.pdf} - $b.pdf"' sh {} \;

$ ls -l
total 0
-rw-r--r--  1 kk  wheel  0 Aug 30 11:31 Boaty McBoatface - arr!.pdf
-rw-r--r--  1 kk  wheel  0 Aug 30 11:30 bingo-night! - hello world.pdf

Running it again would swap the names back to their originals.


Try this

% ls -1                                                                                                       


% rename -n 's/([^-]+)-([^\.]+)\.pdf/$2-$1.pdf/' *.pdf                                                          
001-foobar.pdf -> foobar-001.pdf
002-foobar.pdf -> foobar-002.pdf
003-foobar.pdf -> foobar-003.pdf


(remove -n switch when your tests are OK)

warning There are other tools with the same name which may or may not be able to do this, so be careful.

If you run the following command (GNU)

$ file "$(readlink -f "$(type -p rename)")"

and you have a result like

.../rename: Perl script, ASCII text executable

and not containing:


then this seems to be the right tool =)

If not, to make it the default (usually already the case) on Debian and derivative like Ubuntu :

$ sudo update-alternatives --set rename /path/to/rename

(replace /path/to/rename to the path of your perl's rename command.

If you don't have this command, search your package manager to install it or do it manually

Last but not least, this tool was originally written by Larry Wall, the Perl's dad.

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.