[comp.unix.shell] why does sh do this

pdg@cs.uow.edu.au (Peter Gray) (06/04/91)

I have a question regarding sh and IFS.

From my reading of the man page for sh the following
script should not work.

#!/bin/sh
IFS=":"; export IFS
echo fred
ls fred jim

My understanding is the shell should be looking for
commands "echo fred" and "ls fred jim". But it works fine.
On the ls command fred and jim are treated as 2 arguments.
On the other hand
the shell builtins seem to use the IFS as documented.

EG

echo "fred:jim jack:mary" | (IFS=":"; read a b c; echo "$a\n$b\$c")

produces

fred
jim jack
mary

The SUNOS man page for sh says

     After parameter and command  substitution,  the  results  of
     substitution  are scanned for internal field separator char-
     acters (those found in IFS) and split  into  distinct  argu-
     ments  where such characters are found.  Explicit null argu-
     ments ("" or '')  are  retained.   Implicit  null  arguments
     (those  resulting  from  parameters that have no values) are
     removed.

How does sh actually use IFS??? Why doesn't altering IFS alter
the interpretation of subsequent lines in a script?

pdg

Peter Gray                    Internet: pdg@draci.cs.uow.EDU.AU
Professional Officer          UUCP:     ...!munnari!draci.cs.uow.EDU.AU!pdg  
Dept of Computer Science      MHSnet:   pdg@draci.cs.uow.oz.au
University of Wollongong      Phone: +61 42 213770                       
N.S.W.  2500  Australia       Fax :  +61 42 213262                       

eric@mks.mks.com (Eric Gisin) (06/04/91)

In article <1991Jun4.074041.5300@cs.uow.edu.au> pdg@cs.uow.edu.au (Peter Gray) writes:
   I have a question regarding sh and IFS.

   From my reading of the man page for sh the following
   script should not work.

   #!/bin/sh
   IFS=":"; export IFS
   echo fred
   ls fred jim

   My understanding is the shell should be looking for
   commands "echo fred" and "ls fred jim". But it works fine.
   On the ls command fred and jim are treated as 2 arguments.
   On the other hand
   the shell builtins seem to use the IFS as documented.

---

Right on the first page of sh(1) it says [a command is a list of
words separated by spaces or tabs]. When the script is
read, commands are split into a list of words. This is necessary
so the keywords, assignments, and regular words can be determined.
IFS is used for further splitting when the script is executed.

For example:
	cmd="ls fred jim"
	IFS=" "
	"$cmd"			# one word, "" prevents splitting
	$cmd			# three words, runs ls
	IFS=":"
	$cmd			# one word, does not run ls

andy@xwkg.Icom.Com (Andrew H. Marrinson) (06/05/91)

pdg@cs.uow.edu.au (Peter Gray) writes:

>I have a question regarding sh and IFS.

> [...]

>The SUNOS man page for sh says

>     After parameter and command  substitution,  the  results  of
>     substitution  are scanned for internal field separator char-
>     acters (those found in IFS) and split  into  distinct  argu-
>     ments  where such characters are found.  Explicit null argu-
>     ments ("" or '')  are  retained.   Implicit  null  arguments
>     (those  resulting  from  parameters that have no values) are
>     removed.

Yes, so does the System V man page.  However, earlier, under Commands
it says: ``A simple command is a sequence of non-blank words separated
by blanks.''  And, just above that, under Definitions, it says: ``A
blank is a tab or a space.''  All of this takes place before parameter
and command substitution.  The IFS separators are a different
mechanism, taking place after parameter and command substitution.

>How does sh actually use IFS??? Why doesn't altering IFS alter
>the interpretation of subsequent lines in a script?

It uses it in addition to blank and tab substitution, and at a
different point in processing the command line.  In particular, it
performs splitting with IFS after parameter substition, which explains
why space and tab are in IFS, even though, from the above, it might
seem redundant.  For example, with the default IFS, consider this
sequence of commands:

	foo='xxx yyy'
	echo $foo

The echo here has two arguments, not one, because the splitting by IFS
takes place after parameter substition.  If IFS were changed to :, it
would have just one argument, but then changing foo to xxx:yyy would
cause echo $foo to have two arguments again.

This was weird and somewhat surprising to me, but that it is how it
is.  I didn't understand what was going on until I went back and read
the manual entry, but there it is, clear as mud!
--
		Andrew H. Marrinson
		Icom Systems, Inc.
		Wheeling, IL, USA
		(andy@icom.icom.com)

jfv@cbnewsk.att.com (j.f.van valkenburg) (06/05/91)

I didn't see if you exported the env variable IFS?

This would account for the two results, the first one the IFS set but not
exported and in the second it was local to the shell script.


------------------------
James F. Van Valkenburg         a.k.a.  "van"
AT&T 				Attmail: !jfv               jfv@cbnewsk.att.com
Atlanta, GA.			Voice  404-810-7920
===============================================================================

   ---- Standard Disclaimers included -- Just another grunt at AT&T ----

===============================================================================