I can create multiple numbered folders at once like so:

mkdir Season\ {1,2,3,4,5}

Is there a way I can run the following commands in a oneliner (without a for loop):

mv 01.* Season\ 1
mv 02.* Season\ 2
mv 03.* Season\ 3
mv 04.* Season\ 4
mv 05.* Season\ 5

Bonus points if there's a ZSH way to do it.


With zsh:

autoload zmv # best in ~/.zshrc
zmv -n '(<1-5>).*' 'Season $(($1))'

(remove the -n when happy)

Note that it calls one mv per file so it would be less efficient than the 5 mv commands of your question (unless you do a zmodload zsh/files beforehand to get a builtin mv).

A perl's rename alternative:

rename -n '$_="Season $1/$_" if /0*(\d+)/' 0[1-5].*

(remove -n when happy)

Note that rename calls the rename() system call, so that only works to move files within the same file system (while mv will resort to copy+unlink when moving files across file system boundaries).

With mmv (moving across FS boundary is supported, but then note that not all attributes will be preserved and for symlinks a copy of the target file is created):

mmv -n '0[0-9].*' 'Season #1/'

(remove -n when happy)

  • Nice. I only ever used zmv for renaming files.
    – mafrosis
    Jul 4 '17 at 6:44

You can use printf,xargs combo:

The printf feeds numbers 1 to 5, one at a time -n 1, current number is frozen in {} and then passed onto the sh on it's commandline. The argument is then used to construct the appropriate mv command.

printf '%d\n' {1..5} | xargs -n 1 -I {} sh -c 'mv "0$1".* "Season $1"' {} {}

Here is a bash solution, while loop goes over all seasons and copies files to appropriate folders.

season=0; max_season=5; while (( ((season++)) < ((max_season)) )); do mv 0${season}.* Season\ ${season}; done
  • I suppose I did specify no for loop ;)
    – mafrosis
    Jul 4 '17 at 6:44
  • Actually, that's a zsh solution. In bash, you'd need to quote those parameter expansions unless you can guarantee that code will never be used in contexts where $IFS has been modified (and in bash, you often need to change $IFS as bash doesn't have dedicated splitting operators like in zsh). Jul 4 '17 at 7:02
  • @mafrosis so I did it using while loop :^) Jul 4 '17 at 7:09
  • @StéphaneChazelas my bad, checked where my /bin/sh points to and it's actually dash Jul 4 '17 at 7:11

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.