[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
The IFS variable - a confusing issue.
From: |
cga |
Subject: |
The IFS variable - a confusing issue. |
Date: |
Thu, 07 Oct 2004 13:26:44 -0400 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624 |
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
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
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}:
.. and apparently got the above code to work.
But just to make sure that the modified assignment did what I intended..
I had also added an "echo $IFS" immediately after and this did not give
me the expected result. The IFS variable echoed as ":" - not "
:" as I had anticipated.. or " :".. or even " :" - just ":".
I proceeded to try & check the initial contents of the IFS variable
interactively like so:
$ bash
$ marker=zob
$ echo ${IFS)${marker}
zob
$
This again was not quite what I expected. Since the default contents of
IFS are "space,tab,newline" I thought that the contents of "marker"
would be pushed one line down:
$ echo ${IFS)${marker}
zob
$
I looked for something in bash that would display unprintable variable
contents in one form or another - the ascii code or an escaped sequence
equivalent, but I did not find what I was looking for, so I tried the
following:
$ bash
$ declare -p IFS
declare -- IFS=" \
"
$ ifsave=${IFS}
$ IFS=${IFS}:
$ declare -p IFS
declare -- IFS=" \
"
$ IFS=${ifsave}
$ declare -p IFS
declare -- IFS=" \
"
This would tend to prove that everything does work as I had initially
assumed when I attempted to correct the sample code from the O'Reilly
book. But I am still a bit unsure about my conclusions. As far as I know
my "fix" might work for entirely different reasons..
Could anyone confirm that I got to the bottom of this.. or explain what
I missed or misunderstood?
In particular:
1. The bash man page describes IFS as a special variable. What does the
"special" imply?
2. Is it good bash programming practice to modify, save, and restore the
contents of the IFS variable? It looks like a powerful, elegant
technique but likely to be a source of later headaches if used incorrectly..
3. The bash man page does not mention IFS explicitly when describing the
"for" construct. Am I correct in assuming that "for" uses the contents
of the IFS variable to parse a character string into words?
4. I am still using bash 2.05 but I see in the bash 3.0 Reference Manual
that "word splitting" is now done differently, thus closing a
"longstanding security hole". Where could I find more info concerning
this, in particular regarding whether it affects bash 2.05 and what
exactly was this vulnerability?
I apologize for the verbose post but surely part of the blame must rest
on the authors of the O'Reilly book. I'm sure an experienced bash
programmer would have spotted the error immediately but a newcomer to
the area implicitly trusts the printed word and looks closer to home for
an explanation. Aren't examples supposed to clarify the subject matter
rather than make it more confusing?
Message not available