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: cga
Subject: Re: The IFS variable - a confusing issue.
Date: Sat, 16 Oct 2004 18:58:50 -0400
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

Enrique Perez-Terron wrote:

[...]

Does the syntax

($var)

mean an array with its elements initialized to the contents of 'var' as parsed by the delimiters given by the current contents of IFS?

Only in the context of an assignment.

      "Arrays are assigned to using compound assignments of the form
       name=(value1 ... valuen),"...
Saw that. Then because $(PATH) expands to a set of 'values'.. ok. it makes sense. I admit that I did not see the implication when I read it in the man page.

if IFS=.-_ and var=soft_ware.1.7-10

ar=($var) will cause ar[0] to contain 'soft', ar[1] 'ware', ar[2] '1', ar[3] '7', and ar[4] '10'..??

I just tryied it:

  $ IFS=.-_
  $ var=soft_ware.1.7-10
  $ ar=($var)
  $ for ((i=0; i<${#ar[*]}; i++)); do echo $i: ${ar[i]}; done
  0: soft
  1: ware
  2: 1
  3: 7
  4: 10

Yesss, exactly.
I'm not too fond of using 'set $var' to feed its contents into $1, $2, etc.. Doesn't feel natural. I can't see the implications but it seems that this technique using arrays could be used as a more general alternative to split up a string contained in a variable??

Can't do so right now but i'll have to read my notes and play with it a bit. Otherwise, I wasn't aware of the above C-like variant of the 'for' construct.

But as you see, the language is somewhat inelegant with so much
punctuation characters: ${#ar[*]} just to say the number of elements in
the array 'ar'.

Fortunately bash doesn't have pointers.. Stuff like function returning a pointer to an array of pointers to a function returning a pointer to a char..

Also beware that the array elements need not be contiguously numbered
(they will be if you do ar=($var), but there are other ways):

  $ unset ar[2]
  $ for ((i=0; i<${#ar[*]}; i++)); do echo $i: ${ar[i]}; done
  0: soft
  1: ware
  2:
  3: 7

The '10' is still there at index 4, but since there are now only 4
elements, the loop only tries 0..3.

I don't know how to find out what indices are in use for an array
other than by exhaustive search until you have found the last one.  You
can only know how many there are.  But you can effectively reindex the
array:

  $ ar=("${ar[@]}")
  $ for ((i=0; i<${#ar[*]}; i++)); do echo $i: ${ar[i]}; done
  0: soft
  1: ware
  2: 7
  3: 10
There is still the problem of a possible trailing ':' in PATH.
another 'detail' I completly missed..

There are two things here:
  1. if PATH contains a) a leading :, b) two consecutive ::, or c)
     a trailing :, it is understood that the current directory,
     whatever that is at each moment, is also in the path at the
corresponding place (first, middle, last). This is not really a Bash feature, but a feature of the 'execvp' C library function which is used by bash and virtually all programs that want to start other programs using PATH to locate them.

That I was aware of..

  2. If you set IFS to some set of printable (non-whitespace)
     characters, then each of them is seen as a field *terminator*.
     That means that if IFS=. and var=1.2.3. then there are only three
     words in $var, not four with the last an empty string. But leading
terminators and consecutive terminators do denote the presence of empty elements. I stress non-whitepace because if you have space
     in IFS and var="  a   b " then there are only two words in $var.

This on the other hand I didn't know.

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.

mmm.  obvious..? 'understandable' I woud say..

I meant that some of the other respondents had already said something
about that, so I was really just reiterating.  But if you are new to
these matters, it might have gone a bit above your head :).

It's a hefty dosis you have got, to learn it all in one go. I spent
years doing shell programming, and back then bash did not have half as
many features.

Today I never use bash for seriously complicated things, I use Perl (or
C) instead. In Perl, you _can_ ask for the set of indices in use. Bash
now has got string substitutions using pattern matching. (Look for '%%'
in the manual page, and read a little before and after.)  However, the
language does not give you access to that what was matched, so you
cannot say "put angle brackets around each vowel" even you can say
"vowel" by saying [aeiouy] or similar. You would have to give separate
substitution commands for each vowel: Replace 'a' with '<a>', 'e' with
'<e>', etc. Perl has a superstrong matching and substitution facitlity.
And so it goes on and on.

I believe Python has about the same feature set as Perl, and an easier
(less cluttered and \$#{}-ridden) syntax, but I have not explored it
much. It wasn't available when I discovered Perl, and now I have learned
Perl.  Ruby is yet another Perl-inspired language, kind of Perl++, also
with less clutter.

But Perl (or Python) is not suited as an interactive command line
interpreter, so you still need bash.  For historical reasons, bash, or
some simpler cousin, are among the very first programs installed on a
new computer, and so practically all systems administration, boot
scripts, etc are done in bash or in a historical subset of bash.
For all variations of Unix, (Linux, Solaris, Aix, etc...) you can count
on some program called sh and doing that subset.

Regards,
Enrique
Well thank you very much for all the details. Real world techniques that "feel" native to 
bash such as the examples that you provided is the main thing that's missing from the O'Reilly 
book. Don't know how to put it.. the bash they teach is not very "bash-y".. I guess it's 
not a bad book to read but on the whole it's been rather a disappointment..

Chris






reply via email to

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