Setting IFS for a single statement

点点圈 提交于 2019-12-21 14:12:11

问题


On my GNU bash, version 4.3.42(1)-release I am doing some tests to answer a question. The idea is to split a :-separated string and and each of its elements into an array.

For this, I try to set the IFS to : in the scope of the command, so that the split is automatic and IFS remains untouched:

$ myvar="a:b:c"
$ IFS=: d=($myvar)
$ printf "%s\n" ${d[@]}
a
b
c

And apparently IFS remains the same:

$ echo $IFS
                      # empty

The BASH reference says that:

If IFS is unset, the parameters are separated by spaces. If IFS is null, the parameters are joined without intervening separators.

However, then I notice that the IFS is kind of broken, so that echo $myvar returns a b c instead of a:b:c.

Unsetting the value solves it:

$ unset IFS
$ echo $myvar
a:b:c

But I wonder: what is causing this? Isn't IFS=: command changing IFS just in the scope of the command being executed?

I see in Setting IFS for a single statement that this indeed works:

$ IFS=: eval 'd=($myvar)'
$ echo $myvar
a:b:c

But I don't understand why it does and IFS=: d=($myvar) does not.


回答1:


I was going to comment on this when I saw you use it, but it didn't occur to me until just now what the problem was. The line

IFS=: d=($myvar)

doesn't temporarily set IFS; it simply sets two variables in the current shell. (Simple commands can be prefixed with local environment settings, but an assignment statement itself is not a simple command.)

When you write

echo $IFS

IFS expands to :, but because : is the first character of IFS, it is removed during word splitting. Using

echo "$IFS"

would show that IFS is still set to :.




回答2:


IFS behaves fine with read on the same line:

myvar="a:b:c"
IFS=: read -ra d <<< "$myvar"
printf "%s\n" "${d[@]}"
a
b
c

Check value of IFS:

declare -p IFS
-bash: declare: IFS: not found

so clearly IFS has not been tampered in current shell.

Now check original input:

echo $myvar
a:b:c

or:

echo "$myvar"
a:b:c



回答3:


In bash, you can set set a variable that is valid for a single statement only if that statement is not itself a variable assignment. For example:

$ foo=one bar=two
$ echo $foo
one

To make the second assignment part of a statement, you need ... some other statement. As you've noticed, eval works. In addition, read should work:

$ foo="one:two:three"
$ IFS=: read -r -a bar <<< "$foo"
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three")'


来源:https://stackoverflow.com/questions/33416877/setting-ifs-for-a-single-statement

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!