I have a huge collection of images and I would like to put them in folders matching their first 3 charachers+.jpg extension.

So i would like to grab 4_1_0002.png file (all the files starting with 4_1) and put it in the 4_1_.jpg folder. Similarly I would like to grab 4_2_0002.png file (all the files starting with 4_2) and put it in the 4_2_.jpg folder.

All those files that I would like to sort are now in one huge folder. I expected to use a find command, but I don't know how to extract the first three characters from {} expansion parameter.

find . -type f -ok echo mv {} "path/first3char.jpg" \;

enter image description here

enter image description here


There are tools that make renaming files a lot easier. For example, using any of the Perl rename implementations, often available under the name prename:

prename '$dir = substr($_,0,3); mkdir $dir; $_ = "$dir/$_"' *.jpg

If the directories already exist, you can simplify this to

prename 's!(...)!$1/$1!' *.jpg

If your distribution doesn't carry prename, install one, for example Unicode::Tussle or File::Rename.

find is probably not useful here since the files are all in the same directory. However, you may run into an error because the command line is too long. find is one way to solve this; you can use

find -maxdepth 1 -name '*.jpg' -exec prename 's!(...)!$1/$1!' {} +

Alternatively, run zsh instead of bash, and take advantage of its zmv function.

autoload zmv        # you can put this in ~/.zshrc
mkdir_mv () {
  mkdir -p -- $2:h
  mv -- $1 $2
zmv -p mkdir_mv '(???)*.jpg' '$1/$f'

If the directories already exist, you can use just

zmv '(???)*.jpg' '$1/$f'

mkdir -p "$dest" || exit 1

cd "$src" && \
find . -type f -name '???*' -exec sh -c '
   for f
      [ -d "$dest/$d" ] || mkdir -p "$dest/$d"
      mv "$f" "$dest/$d/."
' x {} +

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.