I have attempted to write a script that renames a list of directories in a folder. It is a bash script and I am only using awk to accomplish this task.

Current form:

[2015] Name of the album

Desired form:

Name of the album - [2015]

My script:

#! /usr/bin/env bash
for f in \[*; do
    mv -t "$f" "$( awk -F '\] ' ' {print $2 " - " $1 "]"}' <<<"$f" )"

When I execute the above script, I get the following error:

mv: cannot stat 'In Dreams [EP] - [1963]': No such file or directory

You don't want -t in your situation. That will tell mv to try to move the desired name to the directory named $f.

It would expand to something like:

mv -t "[2015] Name of the album" "Name of the album - [2015]"

which would be likely what you want without the -t. As is it treats $f as the target directory name into which all the other arguments should be moved.

  • Amazing! I removed the -t option and it worked. Thank you. – GustavMahler May 13 '17 at 12:55

If you have access to perl-rename (called rename on Debian based systems including Ubuntu, perl-rename on Arch and prename on others), you can do:

perl-rename -n 's/(\[.*?\])\s*(.*)/$2 - $1/' ./\[*


  • -n : this makes perl-rename print what it will do without actually renaming anything. Run it like this and, if it looks like it's working as expected, remove the -n to make it actually rename.
  • s/from/to/ : will replace from with to.
  • s/(\[.*?\])\s*(.*)/$2 - $1/' : here, the from is everything between the first [ and the first ] (\[.*?\]). Then 0 or more whitespace characters (\s*) and then everything else (.*). The parentheses around the patters will capture them, letting us use them as $1 and $2 respectively on the right hand side of the substitution. So, that will put everything after the [ ] ($2) before the brackets ($1).
  • ./\[* run it on all files and directories in the current directory whose name begins with a [.

Your solution works if you remove the -t option, as Eric explained.

This is an alternative solution using variable substitutions rather than awk to move the bits of the filename around:

for name in '['*; do
    tag="${name%% *}"
    title="${name#* }"
    mv "$name" "$title - $tag"
  • ${name%% *} removes everything after the first space in $name (including the space), and
  • ${name#* } removes everything before the first space (including the space).

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.