简短回答:更改
IFS
的影响是复杂的,难以理解,除了一些定义良好的习惯用法(例如
IFS=,read ...
),最好避免使用。
长回答:要理解更改
IFS
的结果,需要牢记以下几点:
基于上述内容,IFS=, read -a A
的作用是将其输入按“,”拆分:
$ IFS=, read -a A <<<"alpha,bravo,charlie"
$ declare -p A
declare -a A='([0]="alpha" [1]="bravo" [2]="charlie")'
但是echo
并不关心这些; 它总是在传递参数时添加空格,因此在其前缀中使用IFS=something
没有任何效果:
最初的回答:
$ echo alpha bravo
alpha bravo
$ IFS=, echo alpha bravo
alpha bravo
因此,当您使用
IFS=,echo“${A [*]:1:2}”
时,它相当于只是
echo“${A [*]:1:2}”
,并且由于shell对
IFS
的定义以空格开头,它将
A
的元素放在一起,并使用它们之间的空格。因此,它相当于运行
IFS=,echo“alpha bravo”
。
另一方面,
IFS=,echo“${A [*]:1:2}”
更改了shell对
IFS
的定义,因此它会影响shell如何将元素组合在一起,因此它的输出等效于
IFS=,echo“alpha,bravo”
。不幸的是,它还会影响从那时起的其他所有内容,因此您必须将其隔离到子shell中或在随后将其设置回正常状态。
只是为了完整起见,这里有一些其他无法工作的版本:
$ IFS=,; echo "${A[@]:1:2}"
bravo charlie
在这种情况下,
[@]
告诉shell将数组的每个元素视为单独的参数,因此它留给
echo
来合并它们,并且它忽略
IFS
并始终使用空格。"最初的回答"
$ IFS=,; echo "${A[@]:1:2}"
bravo charlie
那么这样怎么样:
那么这样怎么样:
$ IFS=,; echo ${A[*]:1:2}
bravo charlie
最初的回答:在这种情况下,
[*]
告诉shell使用
IFS
的第一个字符将所有元素合并在一起,得到
bravo,charlie
。但它没有放在双引号中,所以shell会立即按“,”重新分割它,再次将其拆分为单独的参数(然后
echo
像往常一样用空格连接它们)。
如果您想更改shell对
IFS
的定义而不必将其隔离到子shell中,则有几种选项可以更改它,并在之后重新设置它。在bash中,您可以像这样将其设置回正常值:
$ IFS=,
$ while read -a A; do
> echo "${A[*]:1:2}"
> done <<<alpha,bravo,charlie
bravo,charlie
$ IFS=$' \t\n'
然而,$'...'
的语法并不适用于所有shell;如果需要可移植性,最好使用文本字符:
最初的回答
IFS='
' # You can't see it, but there's a literal space and tab after the first '
有些人喜欢使用unset IFS
,这只是强制 shell 还原其默认行为,与以正常方式定义 IFS
几乎相同。
但如果在某个更大的上下文中更改了 IFS
,而您不想搞砸它,那么您需要保存它,然后将其设置回来。如果以正常方式更改了它,则可以使用以下方法:
最初的回答
saveIFS=$IFS
...
IFS=$saveIFS
...但如果有人认为使用unset IFS
是个好主意,那么这将把它定义为空白,导致奇怪的结果。因此,您可以使用这种方法或unset
方法,但不能同时使用两种方法。如果您想使其对抗unset
冲突更加稳健,您可以在bash中使用类似以下内容的方法:
......但是,如果有人认为使用unset IFS
是个好主意,那么这会将其定义为空白,导致出现奇怪的结果。因此,您可以使用这种方法或unset
方法,但不能同时使用两种方法。如果您想让它能够抵御unset
冲突,您可以在bash中使用以下代码:
saveIFS=${IFS:-$' \t\n'}
最初的回答:为了可移植性,请省略
$' '
并使用字面上的空格+制表符+换行符:
saveIFS=${IFS:-
}
总的来说,这是一个充满陷阱的混乱场所。我建议尽可能避免它。"最初的回答"
IFS
在IFS=,echo "${Foo [*]}"
中没有扩展,echo难道不能看到修改后的值吗? - vintnesIFS
。另一种选择是,例如,printf '%s\n' "$(IFS=,; echo "${A[*]:1:2}")
,它仅在命令替换中更改。 - Benjamin W.echo
读取其参数之前,所有这些扩展都会发生。 - vintnes