Question

For college I am writting a script to read and display id3 tags in mp3 files. The arguments would be the files i.e

./id3.sh file1.mp3 file2.mp3 morefiles.mp3

I can read the arguments using $0, $1 etc. and get the number of args with $#. how can I get it to read the output from a ls command?

ls *.mp3 | ./id3.sh
Was it helpful?

Solution

I would suggest using pipe and xargs with -n argument, in the example below the id3.sh script will be called with at most 10 files listed by ls *.mp3. This is very important, especially if you can have hounreds or thousands of files in the list. If you omit the -n 10 then your script will be called only once with the whole list. If the list is too long your system may refuse to run your script. You can experiment how much files in each invokation of your script to process (e.g. what is more efficient in your case).

ls *.mp3 | xargs -n 10 id3.sh

then you can read the files in your id3.sh script like this

while [ "$1" != "" ]; do
    #next file available in ${1}
    shift
done

OTHER TIPS

Try this:

ls *.mp3 | xargs id3.sh

The ls *.mp3 > ./id3.sh command is going to overwrite your id3.sh script with the list of mp3's. You can try this:

./id3.sh `ls *.mp3`

EDIT: actually, what was I thinking? Is there a reason you just can't do this?

./id3.sh *.mp3

Any solution involving the expansion of *.mp3 risks failure if the number of .mp3 files is so large that the resultant expanded *.mp3 exceeds the shell's limit. The solutions above all have this problem:

ls *.mp3 | ...
for file in *.mp3; do ...

In fact, even though ls *.mp3|xargs ... is a good start, but it has the same problem because it requires the shell to expand the *.mp3 list and use that list as command-line arguments to the ls command.

One way to properly handle an arbitrary number of files is:

find . -maxdepth 1 -iname '*.mp3'|while read f; do
    do_something_one_file_at_a_time.sh "$f"
done

OR:

find . -maxdepth 1 -iname '*.mp3' -print0|xargs -0 do_something.sh

(Both variants have the side benefit of properly handling filenames with spaces e.g. "Raindrops Keep Falling On My Head.mp3".

Note that in do_something.sh, you need to do for file in "$@"; do ... and not just for file in $*;do ... or for file in $@; do .... Note also that amit_g's solution breaks if there are filenames with spaces.)

What's wrong with ./id3.sh *.mp3? It's safer than any solution with ls, and provides exactly the same globbing features. There's no need for xargs here, unless you're using an old kernel and have enormous amounts of files.

./id3.sh *.mp3 # if the number of files is not too many

or

ls *.mp3 | xargs -n 10 ./id3.sh # if the number of files could be too many

then in the id3.sh

while [ "$1" != "" ]
do
    filename=$1

    #do whatever with $filename

    shift
done
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top