Is it safe to set IFS for a for loop and then disable it inside a for loop?

Consider the following shell script, which I intend to run on any POSIX.1-2004 compatible shell.

log() { echo debug: "$*" } A=foo:bar:baz IFS=: for i in $A do log token ">> >>" "$i" done unset IFS # Do more stuff here 

I want to iterate over values ​​separated by colons. Inside the loop, I want to call a log function, which should be able to discard all the arguments passed to it intact, with several spaces in each argument stored. When I run this code, this is the result that I get.

 debug: token:>> >>:foo debug: token:>> >>:bar debug: token:>> >>:baz 

It’s good that the two spaces in ">> >>" were saved due to the use of "$*" , i.e. quotes for the asterisk special parameter, as defined in Section 2.5.2 POSIX.1-2004 Special Parameters .

But the bad thing is that as a result of the same use, the three arguments passed to log are now separated by a colon ( IFS ).

I will solve this problem on unset ting IFS in a for loop.

 log() { echo debug: "$*" } A=foo:bar:baz IFS=: for i in $A do unset IFS log token ">> >>" "$i" done unset IFS # Do more stuff here 

Now the result is what I want.

 debug: token >> >> foo debug: token >> >> bar debug: token >> >> baz 

But I want to know if it is possible that in some POSIX shell, canceling IFS inside a for loop can have the side effect of changing IFS for a for loop while it is in progress?

For example, I'm worried that some POSIX shells might print the following output for my second code sample.

 debug: token >> >> foo debug: token >> >> bar:baz 

Can someone tell me, referring to the appropriate sections from POSIX.1-2004 , if my second code example is safe, and if it is guaranteed to create the same behavior in all POSIX-compatible shells?

If my second code example is unsafe, then I may have to agree to something like this that does not change IFS .

 log() { echo debug: "$*" } A=foo:bar:baz echo "$A" | tr : "\n" | while read i do log token ">> >>" "$i" done 
+5
source share
1 answer

It is safe.

The $A variable will expand once before the start of the for-loop:

 for i in foo bar baz 

Once this happens, any changes to the IFS will have no effect.

Refs:
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05

If you use IFS to parse this line, you can do this:

 oldIFS=$IFS IFS=: set -- $A # save the elements of the list as positional parameters IFS=$oldIFS for i; do log "$i" done 
+5
source

Source: https://habr.com/ru/post/1214672/


All Articles