Shell Script – Move Folders Containing Specific File Extensions

scriptshell

Example folder structure:

➜  test tree
.
├── testflac1
│   ├── track1.flac
│   ├── track2.flac
│   └── track3.flac
├── testflac2
│   ├── track1.flac
│   ├── track2.flac
│   └── track3.flac
├── testflac3
│   ├── track1.flac
│   ├── track2.flac
│   └── track3.flac
├── testmp31
│   ├── track1.mp3
│   ├── track2.mp3
│   └── track3.mp3
├── testmp32
│   ├── track1.mp3
│   ├── track2.mp3
│   └── track3.mp3
└── testmp33
    ├── track1.mp3
    ├── track2.mp3
    └── track3.mp3

And the goal would be to move folders that contain one extension to one directory, like ~/test [FLAC] and others containing mp3 extension to ~/test [MP3]. I tried out doing that with find, but that only allowed me to do move files themselves, without retaining folder structure.

Best Answer

Try:

shopt -s nullglob; for dir in path/to/*/; do files=("$dir"/*{mp3,flac}); [ "${files[0]}" ] && mv "$dir" ~/test; done

Or, for those who prefer their commands spread over multiple lines:

shopt -s nullglob
for dir in path/to/*/
do
    files=("$dir"/*{mp3,flac})
    [ "${files[0]}" ] && mv "$dir" ~/test
done

Before running that, of course, change path/to/ to whatever gets you to your test dir as shown in the question. Then, path/to/*/ should expand to all the directories of interest.

How it works

  • shopt -s nullglob

    This sets nullglob so that a pathname expansion that returns no files will return an empty string.

  • for dir in path/to/*/; do

    This starts a loop over all directories in your test dir.

  • files=("$dir"/*{mp3,flac})

    This creates an array whose elements are any file names in $dir that end in mp3 or flac.

  • [ "${files[0]}" ] && mv "$dir" ~/test

    If the array files is not empty (meaning that there is at least one mp3 or flac file in the directory), then move directory dir to ~/test.

  • done

    This signals the end of the loop.

Related Question