Best way to change IFS for a for loop in Bourne shell

Best way to change IFS for a for loop in Bourne shell

Post by Frederick W. Wheel » Wed, 03 Mar 1999 04:00:00



I have a for loop in a Bourne shell script that needs to use a colon
separated list.  I'm wondering if I'm changing and reseting the IFS
right because my solution seems kludgy.  Does anyone know a better
way?

list="foo -opt1:bar -opt2:baz -opt3"

origIFS=$IFS
IFS=':'
for x in $list; do
  # reset IFS here because commands in the loop rely on IFS being the default
  IFS=$origIFS
  echo $x
  # more stuff in here that relies on IFS being the default
done
# need to reset IFS here in case list is empty and for loop not executed
IFS=$origIFS

I was very surprised that the following did not work.  The error
message I get is "do unexpected".

IFS=':' for x in $list; do
  echo $x
done

I don't think it matters, but just in case, my system is:

% uname -a
SunOS seurat 5.6 Generic_105181-03 sun4u sparc
% which sh
sh is /usr/bin/sh

Thanks,
Fred Wheeler

--
Fred Wheeler
wheeler (at) cipr.rpi.edu
www.cipr.rpi.edu/wheeler

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Angela Schwar » Wed, 03 Mar 1999 04:00:00



> I have a for loop in a Bourne shell script that needs to use a colon
> separated list.  I'm wondering if I'm changing and reseting the IFS
> right because my solution seems kludgy.  Does anyone know a better
> way?

> list="foo -opt1:bar -opt2:baz -opt3"

> origIFS=$IFS
> IFS=':'
> for x in $list; do
>   # reset IFS here because commands in the loop rely on IFS being the default
>   IFS=$origIFS
>   echo $x
>   # more stuff in here that relies on IFS being the default
> done
> # need to reset IFS here in case list is empty and for loop not executed
> IFS=$origIFS

> I was very surprised that the following did not work.  The error
> message I get is "do unexpected".

> IFS=':' for x in $list; do
>   echo $x
> done

> I don't think it matters, but just in case, my system is:

> % uname -a
> SunOS seurat 5.6 Generic_105181-03 sun4u sparc
> % which sh
> sh is /usr/bin/sh

> Thanks,
> Fred Wheeler

> --
> Fred Wheeler
> wheeler (at) cipr.rpi.edu
> www.cipr.rpi.edu/wheeler

I'm not sure if I unterstand what you want to do. I expect the
following: first x="foo -opt1", second x="bar -opt2", ...

What about replacing all spaces first by perhaps "+" and all ":" by
sopaces. In your loop, you can than replace the "+" by space. So you
don't have to change your IFS.

for y in `echo $list | sed -e 's/ /+/g' -e 's/:/ /g'`; do
  x=`echo $y | sed 's/+/ /g'`
  echo $x
done

        Angela

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Frederick W. Wheel » Wed, 03 Mar 1999 04:00:00


Let me it clear that the following loop works.  It does what I want it
to do, printing:

foo -opt1
bar -opt2
baz -opt3

It just seems kludgy to have to set and restore IFS the way I do.  I'm
looking for a simple way to get IFS-: applied to the $list variable
expansion in the for loop and nowhere else.


Quote:> list="foo -opt1:bar -opt2:baz -opt3"

> origIFS=$IFS
> IFS=':'
> for x in $list; do
>   # reset IFS here because commands in the loop rely on IFS being the default
>   IFS=$origIFS
>   echo $x
>   # more stuff in here that relies on IFS being the default
> done
> # need to reset IFS here in case list is empty and for loop not executed
> IFS=$origIFS

Thanks,
Fred Wheeler

--
Fred Wheeler
wheeler (at) cipr.rpi.edu
www.cipr.rpi.edu/wheeler

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Donn Ca » Wed, 03 Mar 1999 04:00:00



| I have a for loop in a Bourne shell script that needs to use a colon
| separated list.  I'm wondering if I'm changing and reseting the IFS
| right because my solution seems kludgy.  Does anyone know a better
| way?
|
| list="foo -opt1:bar -opt2:baz -opt3"
|
| origIFS=$IFS
| IFS=':'
| for x in $list; do
|   # reset IFS here because commands in the loop rely on IFS being the default
|   IFS=$origIFS
|   echo $x
|   # more stuff in here that relies on IFS being the default
| done
| # need to reset IFS here in case list is empty and for loop not executed
| IFS=$origIFS

You're sure right about kludgy, but the only thing I can suggest (I do
this not infrequently myself) is to replace the argument list:

origIFS=$IFS
set $list
IFS=$origIFS
for x
do ...

If you can't discard the actual argument list at this point, and your shell
doesn't have array capabilities anywhere else, the only other approaches I
can think of are even worse.  You could get something to work along the lines
of replace : with newlines, and replace "for x" with "while read x", but it
would be no great step forward.

| I was very surprised that the following did not work.  The error
| message I get is "do unexpected".
|
| IFS=':' for x in $list; do
|   echo $x
| done

That syntax is to my knowledge only valid for assignment of environment
variables for a command statement, which "for" is not.

        Donn Cave, University Computing Services, University of Washington

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Ken Pizzi » Wed, 03 Mar 1999 04:00:00


On 02 Mar 1999 08:35:18 -0500,

Quote:

>I have a for loop in a Bourne shell script that needs to use a colon
>separated list.  I'm wondering if I'm changing and reseting the IFS
>right because my solution seems kludgy.  Does anyone know a better
>way?

>list="foo -opt1:bar -opt2:baz -opt3"

>origIFS=$IFS
>IFS=':'
>for x in $list; do
>  # reset IFS here because commands in the loop rely on IFS being the default
>  IFS=$origIFS
>  echo $x
>  # more stuff in here that relies on IFS being the default
>done
># need to reset IFS here in case list is empty and for loop not executed
>IFS=$origIFS

Depending on whether or not you need to access the pre-existing argument
list at or after this point in the script, you might be able to use:
 origIFS="$IFS"
 IFS=':'
 set -- $list
 IFS="$origIFS"
 for x; do
   echo $x
   # more stuff in here that relies on IFS being the default
 done
 # more stuff here that relies on IFS being the default

Not a huge win in terms of complexity, but at least all the IFS
games are localized in one place, rather than scattered hither
and yon.

                --Ken Pizzini

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Dale Hagglun » Wed, 03 Mar 1999 04:00:00



> | I was very surprised that the following did not work.  The error
> | message I get is "do unexpected".
> |
> | IFS=':' for x in $list; do
> |   echo $x
> | done

> That syntax is to my knowledge only valid for assignment of environment
> variables for a command statement, which "for" is not.

I just happened to think of this off the top of my head.  It seems to work.


        do
                echo $f
        done

I'm not sure this counts as better or worse than any of the other
solutions I've seen.  It does avoid the problem of saving/restoring
IFS, at the expense of a subshell.

Dale.

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by brian hile » Wed, 03 Mar 1999 04:00:00





>    do
>            echo $f
>    done

My favorite scripting idiom for the above situation is:

IFS=: eval "set -- \$list; IFS='$IFS'"        # "list" is your colon-delimited list var

No temporary variables holding IFS; no setting and resetting of
IFS per a scope of code; no unnecessary processes or process
environments or external software.... Now that the hard work is
done:

for list_element
do      # do anything here; IFS is always set to default ...
done

-Brian

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Dale Hagglun » Wed, 03 Mar 1999 04:00:00



> My favorite scripting idiom for the above situation is:
>    IFS=: eval "set -- \$list; IFS='$IFS'"
> No temporary variables holding IFS; no setting and resetting of
> IFS per a scope of code; no unnecessary processes or process
> environments or external software....

Hey, I like this one.  Mine had other problems to, I think, if the
various fields happened to contain whitespace.  

Why do you need the IFS assignment in the eval string though?  It
seems to work fine without it for me, as in

        IFS=: eval 'set -- $list'

Dale.

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Donn Ca » Thu, 04 Mar 1999 04:00:00




|>   do
|>           echo $f
|>   done

I didn't write any of that, contrary to the apparent attribution.
The problem with the suggested usage is that the output of the `` gets
split, again, this time on white space.  If there is any white space
in there, you lose.  /etc/passwd is a better example of this than PATH.

| My favorite scripting idiom for the above situation is:
|
| IFS=: eval "set -- \$list; IFS='$IFS'"  # "list" is your colon-delimited list var
|
| No temporary variables holding IFS; no setting and resetting of
| IFS per a scope of code; no unnecessary processes or process
| environments or external software.... Now that the hard work is
| done:

OK, but it seems to me like a lot of trouble to avoid a temporary variable,
compared to the IFS based approach the original poster was already using.
I guess there's always going to be some difference of opinion on questions
maintainability and elegance, maybe I react too strongly to "eval".

        Donn Cave, University Computing Services, University of Washington

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by brian hile » Thu, 04 Mar 1999 04:00:00




>> My favorite scripting idiom for the above situation is:
>>        IFS=: eval "set -- \$list; IFS='$IFS'"
> Hey, I like this one.  Mine had other problems to, I think, if the
> various fields happened to contain whitespace.  

Thank you. For every submission of a good idea I have made to
c.u.s., I assure you I have received three from it!

Quote:> Why do you need the IFS assignment in the eval string though?  It
> seems to work fine without it for me, as in
>    IFS=: eval 'set -- $list'

Technically, one does not need to include the "eval" or for that
matter the reassignment of the IFS variable; however, the side-efect
of the above will be to change the IFS variable--and the scripting
idiom I submitted exists to transparently parse field delimiters
without making these. As a scripting idiom, one merely need to
"substitute the parameters" and not worry about consequences.
Command verbosity is made up by benignity.

The "eval" is there for the necessity of resetting the IFS value
to the original value_and_ performing a "set ..." _in the same
instruction_.

P.S. Unfortunately the above will not work as written in bash, as
Chet Ramey has not seen fit to implement the documented feature "special
shell builtins" as he cannot think of why anyone would what to use
this facility. Hmmm.

-Brian

 
 
 

Best way to change IFS for a for loop in Bourne shell

Post by Chet Ram » Thu, 04 Mar 1999 04:00:00




Quote:>P.S. Unfortunately the above will not work as written in bash, as
>Chet Ramey has not seen fit to implement the documented feature "special
>shell builtins" as he cannot think of why anyone would what to use
>this facility. Hmmm.

Don't be deliberately disingenuous.  This feature is available when
bash is in posix mode, and is documented.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
( ``Discere est Dolere'' -- chet)


 
 
 

1. setting IFS to newline in bourne shell

Hi,

I hope someone could help me out please.  I have simple script to read a
file.  I want to read each line of the file, but it does not seem to be
doing that due to IFS setting.  The default is space, tab, and newline.  How
do I change it to newline only.  I tried almost everything without much
result.

SCRIPT:
for i in `cat file` ; do
echo $i   #want to see line read here, but does not
done

Any help is greatly appreciated.

Thanks,
Cuong

2. ED4D5360 AutoCAD for Linux

3. Light Speed Bourne Shell! (was: Bourne shell tricks)

4. rxvt problem

5. Changing from the Bourne shell to C-shell

6. bootup oops with current BK

7. Unix History Question for Unix Professionals

8. loop in Bourne shell script

9. Bourne Shell Problem - variable not incrementing within a while loop

10. bourne shell script question re: for-in loop

11. Bourne Shell 'for' loop problem.

12. Bourne Shell - counter number varibales in a for loop