bug-bash
[Top][All Lists]
Advanced

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

Re: The IFS variable - a confusing issue.


From: Enrique Perez-Terron
Subject: Re: The IFS variable - a confusing issue.
Date: Sat, 16 Oct 2004 15:42:46 +0200

On Thu, 2004-10-07 at 19:26, cga wrote:
> I ran into this code snippet in "Learning the Bash Shell" - Cameron 
> Newham & Bill Rosenblatt - O'Reilly (page 248):
> 
>       1 #!/bin/bash2
>       2 IFS=:
>       3 for d in $PATH; do
>       4         echo checking $d:
>       5         cd $d
>       6         scripts=$(file * | grep 'shell script' | cut -d: -f1)
>       7         for f in $script do
                                ^^^^
You probably actually had
>       7         for f in $scripts; do

>       8                 grep '\^' $f /dev/null
>       9         done
>      10 done
> 
> This did not work in my setup - in my mind because while the list used 
> for the external "for" loop (line 1/10) uses ":" as a separator 
> (PATH="dir1:dir2:dir3"..) the pipeline on line 6 generates a 
> space-delimited list of files - i.e. "file1 file2 file3 ... file99" but 

The list is newline-delimited.  (Just for the record, your point still
applies.)

> unfortunately, since the IFS variable now contains only ":" this leads 
> the "for" command on line 7 to believe that it is dealing with a 
> one-item list ("file1 file2.. etc") and the ensuing "grep" attempts to 
> search a file named "file1 file2 .. file99" - in my case causing it to 
> fail with a "file name too long" message.
> 
> I replaced line 2 by the following:
> 
>        2 IFS=${IFS}:

You could try the following:

         2 IFS=: eval "list=(\$PATH)"
         3 for d in "${list[@]}"; do

(Sorry for the massive punctuation needed.)

It has the advantage of not changing IFS other than for the eval
command.  

It also has the advantage of allowing directory names with spaces in
them.

The eval is necessary (rather than just 'IFS=: list=($PATH)') because 
1) a command like 'A=foo B=bar' is equivalent to 'A=foo; B=bar;',
   ie. the assignments are permanent, and
2) You need to delay the expansion and word splitting of $PATH 
   until IFS=: is in effect, which also explains the backslash 
   in front of the $.

If you wonder what the parentheses in "list=($PATH)" do there, you
probably have not yet read about shell array variables. Man bash, and
search for one-dimensional.

There is still the problem of a possible trailing ':' in PATH. Only one
trailing delimiter is discarded, so you could do

         2 IFS=: eval "p=\"$PATH:\" list=(\$p)"
         3 for d in "${list[@]}"; do

Finally you would add 

        3b      if [ -z "$d" ]; then d=.; fi

but that is probably obvious by now.

> an explanation. Aren't examples supposed to clarify the subject matter 
> rather than make it more confusing?

Shame on Cameron Newham & Bill Rosenblatt, and on O'Reilly as well.

Regards,
Enrique





reply via email to

[Prev in Thread] Current Thread [Next in Thread]