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

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 :-) – Nikhil Mulley Mar 3 '12 at 10:43
  • @Chris-down, darn that is awesome :) – user14517 Mar 3 '12 at 14:16
  • @Chirs Down, Awesome sir :) – user1228191 Mar 3 '12 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 – user1228191 Mar 3 '12 at 9:34
  • Oh. Nice catch. I'll work on it. – user14517 Mar 3 '12 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 '12 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 '12 at 10:34
  • 1
    Yes, it will. Don't parse ls! – Chris Down Mar 3 '12 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 '12 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? – Gilles 'SO- stop being evil' Mar 3 '12 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 '12 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 '12 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.