How can I pass a list of directories to a find command?

Imagine you got the list as:

ls -d mydir*/

which would output mydir1, mydir2 and so on, but exclude otherdirs1, otherdirs2.

I'd like to run the following command on the list:

find <put here the name of each dir>  -type f -name "*.mp3" -print0 | xargs -0 ...

Trying to run this command on each directory separately:

find -type f -name "*.mp3" -print0 |
xargs -0  mplayer -vo dummy -ao dummy -identify 2>/dev/null |
 perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1) && printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60' |
 tail -n 1

That means: find the mp3s, run mplayer to obtain meta-data on each file, sum all ID_LENGTH of each mp3 file, output sum of all mp3s in directory.


ls -d lists exactly what you passed it (except for the non-existing files). So assuming that there is at least one directory whose name begins with mydir, it's simply

find mydir*/ -type f -name .mp3 -print0 | …

Note that mydir*/ matches symbolic links to directories, and find will traverse the linked directories.

Normally xargs runs the command as few times as possible, passing it multiple arguments at a time. If you need to run the command for each file separately, tell it so:

find mydir*/ -type f -name .mp3 -print0 |
xargs -0 -n1 mplayer … |
perl …

Or do the simple thing and use the -exec option of find. You do lose the ability to filter the errors from find and from mplayer separately.

find mydir*/ -type f -name .mp3 -exec mplayer -vo dummy -ao dummy -identify {} \; 2>/dev/null |
perl …

By the way, why print all the lines if you only need the last one?

… | perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1); END {printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60}'

In bash after running shopt -s globstar, in ksh after running set -o globstar, or in zsh out of the box, you can also use ** to match files in subdirectories recursively.

mycommand mydir*/**/*.mp3
for f in mydir*/**/*.mp3; do …

This also matches directories and symbolic links whose name ends in .mp3. Bash traverses symbolic links to directories while ksh and zsh do traverse mydir* if they're symbolic links to directories but omit symbolic links when recursing.

for f in mydir*/**/*.mp3; do
  mplayer -vo dummy -ao dummy -identify "$f" 2>/dev/null
done | perl …

ksh93 and zsh (but not bash, dash or pdksh) have floating point arithmetic, so you don't even need to invoke another tool such as Perl to do the sum.

typeset -F length=0
for f in mydir*/**/*.mp3; do
  length+=$(mplayer -vo dummy -ao dummy -identify "$f" 2>/dev/null |
            sed -n 's/^ID_LENGTH=//p')
done | perl …
printf "%02d:%02d:%02d\n" $((t/3600)) $((t/60%60)) $((t%60))
  • Yes, that helps. However, I still have to run the find command on each single directory separately. The xargs's part above is: find . -type f -name "*.mp3" -print0 | xargs -0 mplayer -vo dummy -ao dummy -identify 2>/dev/null | perl -nle '/ID_LENGTH=([0-9\.]+)/ && ($t +=$1) && printf "%02d:%02d:%02d\n",$t/3600,$t/60%60,$t%60' | tail -n 1 So, I want to know the output of each command, for example mydir1: 4:44, mydir2: 81:33 and so on. – Quora Feans Sep 6 '13 at 1:15
  • I'm having trouble parsing your command without formatting. Do you want to run mplayer once per directory or once per mp3 file? If it's once per directory, then call the pipeline in a loop: for d in mydir*/; do find "$d" -name .mp3 -print0 | xargs …. If it's once per file, then you don't need to run separate find commands: you need to tell xargs to run a new instance of mplayer for each file, or simpler, use -exec instead of xargs. – Gilles 'SO- stop being evil' Sep 6 '13 at 1:27
  • Ok, I expanded my question, explaining better the command. It has to run mplayer on each file. – Quora Feans Sep 6 '13 at 1:43
  • @QuoraFea See my updated answer. – Gilles 'SO- stop being evil' Sep 6 '13 at 7:10
  • that's OK for knowing the total length of all mp3, but still leaves me without knowing a break down by each directory. How can I generate a table as dir1: 12:02, dir2: 03:45 and so on? – Quora Feans Sep 6 '13 at 12:33

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.