问题
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