[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Handle each file at a time in loop?



On Tue, Jan 05, 2010 at 02:00:31AM +0530, Foss User wrote:
> for file in `ls *.wav`
> do
>     echo $file
> done
>
> Of course, this doesn't do what I need. The names are
> split wherever there are spaces.
> 
> $ sh convert.sh
snip
> What is the right way to do this?

Aside from correctly quoting your variables (as others have
pointed out), you could also use a combination of find(1)
and xargs(1). This is a generally robust approach for files
which might have any number of awkward characters in the
names: spaces, unprintable characters, files beginning with
dashes (which programs might mistake/confuse for arguments),
etc.

Especially if you are doing some kind of encoding (as
convert.sh + .wav files suggests) and have a multi-core
system. In this situation, the '-P' argument to GNU xargs is
a nice feature for parallel execution. E.g.

    $ find . -type f -name '*.wav' -print0 | xargs -r0 -n 1 -P 4 lame -S

Here find generates a list of files in the current directory
ending in '.wav', prints out a string with the filenames
embedded in it, separated by the NULL byte (so guaranteed
not to be part of a filename itself); xargs then takes this
string and splits it up into filenames, then, assuming there
is at least one argument, runs 'lame -S <file>' for each
file, four invocations at a time[1]. 

For renaming (to remove .wav from inside foo.wav.mp3, or to
remove the space characters to make files easier to handle),
you might like rename(1) from inside the perl package:

    $ rename 's/ /_/g' *wav
    $ rename 's/\.wav//' *mp3

[1] the exact number you want to use is a matter of
    experimentation; number of cores - 1 might be good if
    you want to guarantee CPU time to other tasks e.g.
    interactive usage; I tend to use number of (cores * 2) -
    1 i.e. 7 for a quad-core/hyper-threaded machine


-- 
Jon Dowland

Attachment: signature.asc
Description: Digital signature


Reply to: