Loop over file names from `find`?

2019-04-09 22:44发布

问题:

If I run this command:

sudo find . -name *.mp3

then I can get a listing of lots of mp3 files.

Now I want to do something with each mp3 file in a loop. For example, I could create a while loop, and inside assign the first file name to the variable file. Then I could do something with that file. Next I could assign the second file name to the variable file and do with that, etc.

How can I realize this using a linux shell command? Any help is appreciated, thanks!

回答1:

For this, use the read builtin:

sudo find . -name *.mp3 |
while read filename
do
    echo "$filename"    # ... or any other command using $filename
done

Provided that your filenames don't use the newline (\n) character, this should work fine.



回答2:

My favourites are

find . -name '*.mp3' -exec cmd {} \;

or

find . -name '*.mp3' -print0 | xargs -0 cmd

While Loop

As others have pointed out, you can frequently use a while read loop to read filenames line by line, it has the drawback of not allowing line-ends in filenames (who uses that?).

xargs vs. -exec cmd {} +

Summarizing the comments saying that -exec...+ is better, I prefer xargs because it is more versatile:

  • works with other commands than just find
  • allows 'batching' (grouping) in command lines, say xargs -n 10 (ten at a time)
  • allows parallellizing, say xargs -P4 (max 4 concurrent processes running at a time)
  • does privilige separation (such as in the OP's case, where he uses sudo find: using -exec would run all commands as the root user, whereas with xargs that isn't necessary:

    sudo find -name '*.mp3' -print0 | sudo xargs -0 require_root.sh
    sudo find -name '*.mp3' -print0 | xargs -0 nonroot.sh
    
  • in general, pipes are just more versatile (logging, sorting, remoting, caching, checking, parallelizing etc, you can do that)



回答3:

How about using the -exec option to find?

find . -name '*.mp3' -exec mpg123 '{}' \;

That will call the command mpg123 for every file found, i.e. it will play all the files, in the order they are found.



回答4:

for file in $(sudo find . -name *.mp3);
do
    # do something with file
done