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

Re: Unix-ify File Names



Mike McClain <mike.mcclain@nowhere.net>:
> Frank Terbeck <ft@bewatermyfriend.org> wrote:
>
> > >  for FILE in `ls *$1` ; do
> >
> > Please don't teach beginners to do for loops like this. It's broken in
> > various ways. Just do:
> >
> >   for FILE in *"$1" ; do
> >
>
> Being a self taught script writer I just have to ask what are the
> 'various ways' in which the first form is broken?

a) `ls *` is an _external_ process.

    And performance is not the main reason we this is bad.
    It would have to be a lot of forks to make a notable difference.

    However, the big problem here is, that you can only pass a limited
    number of arguments to an external program. This limit is reached
    quicker than you might think, and it is one of the features of
    for-loops to _overcome_ this limitation.

b) it breaks on filenames with spaces (and other special characters).

    While newlines and other special characters might be rather weird
    for filenames, spaces are perfectly okay and normal in filenames.

    Using 'for i in `ls *`'-type loops breaks this and is one of the
    main reasons why people think spaces are bad in filenames.
    (They are not bad, some people just do not know how to handle
    them properly.)

c) people commonly use 'ls --color' or 'ls -F' aliases for ls.

    This is not a bad thing in the first place because it helps to
    simplify the overview you get from ls.

    However, it has a bad impact on scripting:
[snip]
% for i in `ls -F /bin/*sh` ; do stat "$i" ; done
stat: cannot stat `/bin/sh@': No such file or directory
% for i in `ls --color /bin/sh` ; do stat "$i" ; done
stat: cannot stat `\033[00m\033[01;36m/bin/sh\033[00m': No such file or directory
stat: cannot stat `\033[m': No such file or directory
[snap]

    Using '--color=auto' instead of just '--color' helps a little
    with problem, but not everyone is aware of it.

    Yes, I know that aliases are normally not enabled in scripts, but
    for-loops are very handy as one-liners, so this _is_ indeed a
    problem.

These are the main reasons that come to my mind. There might be
others. I am aware that there are HOWTOs and other documents out there
that propagate 'for i `ls *foobar*`' loops. I don't know why their
authors do this. If they didn't know better they shouldn't have
written a shell scripting HOWTO in the first place.

Some people use things like this instead:
[snip]
ls * | while read file ; do whatever_command "$file" ; done
[snap]

This is just a little better than the for loop. It still breaks in
some situations. Also 'for i in * ; do foo "$i" ; done' is much
clearer, shorter and simpler to understand.

There is _no_ reason why 'ls' should ever be used to generate file
lists for loops of any kind.
Whoever created this myth should be hung. :-)

Oh, and doing the following will break in certain situations as well
(which is something people do for recursive actions):
[snip]
find . -name '*' | while read file ; do foobar "$file" ; done
[snap]

If you need to do recursive actions, learn to use find(1) properly
(with its '-exec' option), or switch to a shell, that can do it by
itself (like zsh, for example).

Regards, Frank

-- 
In protocol design, perfection has been reached not when there is
nothing left to add, but when there is nothing left to take away.
                                                  -- RFC 1925



Reply to: