It was a mess of music files and directory.

It is needed to perform the below operation over multiple directories at once:

  1. If the directory contains ".jpg" files, then create a new directory "Covers" and move those files into it.
  2. If the directory does not contain any ".jpg" files, don't create "Covers" directory
  3. If the directory already contains "Covers" directory, don’t create "Covers" directory

3 Answers 3


In bash:

shopt -s nullglob
for dir; do
    [[ -d $dir ]] || continue
    jpgs=( "${dir}"/*.jpg )
    if (( "${#jpgs[@]}" )); then
        [[ -d ${dir}/Covers ]] || mkdir "${dir}/Covers"
        # Avoiding race condition by not reusing the jpgs array
        for jpg in "${dir}"/*.jpg; do
            mv "$jpg" "${dir}/Covers"
  • pretty simple and neat, @Chris-down :-) Mar 3, 2012 at 10:43
  • @Chris-down, darn that is awesome :)
    – user14517
    Mar 3, 2012 at 14:16
  • @Chirs Down, Awesome sir :) Mar 3, 2012 at 15:09

I am still a rookie but here is mine:

#echo $current_directory
(find -maxdepth 1 -type d -name '*' ! -name '.*' -printf '%f\n')>filelist
number=$(find -maxdepth 1 -type d -name '*' ! -name '.*' -printf '%f\n' | wc -l)
for iteration in `seq $number`
    fname=$(head -1 filelist)
    sed 1d < filelist > filelist2
    mv filelist2 filelist
    cd "$fname"
    if [ -z $(ls | grep -i jpg) ]
    then echo "Doing nothing as there are no JPG files....."
        total=$(ls -l|grep -i jpg | wc -l)
        mkdir -p Covers
        mv *.jpg Covers
        echo "Moved $total JPG Files....."
    cd "$current_directory"

Simply go into the main music directory and execute this script.

No need to pass any arguments

EDIT: It was sloppy before. It is sloppier now. But I think it will work.

  • Thanks its very nice, Same question for you too : How to get handle those directory names which contains spaces in its name Mar 3, 2012 at 9:34
  • Oh. Nice catch. I'll work on it.
    – user14517
    Mar 3, 2012 at 9:53
  • Do not parse ls, it is dangerous and will break easily. Use a glob. See mywiki.wooledge.org/ParsingLs
    – Chris Down
    Mar 3, 2012 at 10:18
  • 1
    Also, you need to quote $current_directory, or it will break if the path has spaces in.
    – Chris Down
    Mar 3, 2012 at 10:34
  • 1
    Yes, it will. Don't parse ls!
    – Chris Down
    Mar 3, 2012 at 11:02


#work in current dir if work path was not provided  
[ $# -eq 0 ] && search_path="." || search_path="$1"  

# files to be moved, more extensions can be added  

move_jpg() {  
    # create "Covers" if it doesn't exist  
    [ -d "$1/Covers" ] && echo -n " ... " || { echo -n " ...create Covers ";   mkdir "$1/Covers" }  

    mv "$1/$wildcard" "$1/Covers/$wildcard"  
    echo "... files moved"  

for d in "$search_path/*/"; do  

    echo -n "testing <$d>   "  

    [ -e "$d/$wildcard" ] && ${move_jpg "$d"} || echo "...Not found <$wildcard>"  


  • 1
    Using command substitution with find will break very easily. Do not do it.
    – Chris Down
    Mar 3, 2012 at 10:19
  • Instead of calling find, which will break on all kinds of file names, write for d in "$search_path"/*/; the final / restricts the matching to directories. I wonder where IFS=$(echo -en "\n\b") comes from (by the way, you can write this in a simpler way: IFS=$'\n\b'): what's the point in making backspace a field separator? Mar 3, 2012 at 23:51
  • didn't know about trick with last slash, will use it, thanks. of cause, IFS=$(echo ...) can be easily replaced to just assignement. corrected.
    – vasily-vm
    Mar 6, 2012 at 16:53
  • "Using command substitution with find will break very easily" don't understand this :( how find can be broken in such situation?
    – vasily-vm
    Mar 6, 2012 at 16:57

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.