Answers:
其基本思路是,VAR=VALUE some-command
套VAR
到VALUE
了执行some-command
的时候some-command
是一个外部命令,它没有得到比这更花哨。如果您将这种直觉与壳的工作原理相结合,则在大多数情况下应该给出正确的答案。POSIX参考是“ Shell命令语言”一章中的“简单命令”。
如果some-command
是外部命令,VAR=VALUE some-command
则等效于env VAR=VALUE some-command
。VAR
是在的环境中导出的some-command
,并且其在shell中的值(或缺少值)不变。
如果some-command
是函数,则VAR=VALUE some-command
等价于VAR=VALUE; some-command
,即函数返回后,赋值保持不变,并且变量不会导出到环境中。这样做的原因与Bourne shell的设计有关(并因此具有向后兼容性):它不具有在执行函数时保存和恢复变量值的功能。不导出变量是有意义的,因为函数是在Shell本身中执行的。但是,ksh(包括ATT ksh93和pdksh / mksh),bash和zsh会实现更有用的行为,其中VAR
仅在执行函数时设置(也将其导出)。在ksh中,如果使用ksh语法定义了函数,则可以完成此操作function NAME …
,而不是使用标准语法定义的NAME ()
。在bash中,只能在bash模式下完成此操作,而在POSIX模式下则不能(使用时运行POSIXLY_CORRECT=1
)。在zsh中,如果posix_builtins
未设置该选项,则完成此操作;此选项不是默认设置,而是由emulate sh
或启用emulate ksh
。
如果some-command
是内置的,则行为取决于内置的类型。特殊的内置函数的行为类似于函数。特殊的内置组件是必须在外壳程序内部实现的,因为它们会影响状态外壳程序(例如,break
影响控制流,cd
影响当前目录,set
影响位置参数和选项……)。其他内置插件仅是为了提高性能和方便性而内置(大多数情况下-例如bash功能printf -v
只能由内置插件实现),并且它们的行为类似于外部命令。
分配是在别名扩展之后进行的,因此,如果some-command
是别名,请首先对其进行扩展以查找发生的情况。
请注意,在所有情况下,分配都是在解析命令行后执行的,包括命令行本身上的任何变量替换。因此var=a; var=b echo $var
打印a
,因为$var
在分配发生之前进行了评估。从而IFS=. printf "%s\n" $var
使用旧IFS
值进行拆分$var
。
我已经介绍了所有类型的命令,但还有另外一种情况:没有命令要执行时,即,如果该命令仅由分配(和可能的重定向)组成。在这种情况下,分配保持不变。VAR=VALUE OTHERVAR=OTHERVALUE
等同于VAR=VALUE; OTHERVAR=OTHERVALUE
。所以之后IFS=. arr=($var)
,IFS
仍然设置为.
。由于您可以$IFS
在分配中arr
使用并期望它已经具有新值,因此将的新值IFS
用于的扩展是有意义的$var
。
总之,您只能将其IFS
用于临时字段拆分:
third=$(IFS=.; set -f; set -- $var; echo "$3")
是一种复杂的方法,third=${var#*.*.}
除了当值var
少于两个.
字符时它们的行为不同);IFS=. some-function
where some-function
用ksh语法定义function some-function …
;IFS=. some-function
只要它们以纯模式(而不是兼容模式)运行。他(详细解释)一个复杂的问题,@ Gilles的回答确实很棒。
但是,我相信为什么使用此命令的答案是:
$ IFS=. printf "%s\n" $var
a.b.c
这样做是一个简单的想法,即在执行整个命令行之前先对其进行分析。并且每个“单词”都由外壳处理一次。像这样
的分配IFS=.
被延迟了(步骤4是最后一个):
4.-每个变量分配应扩展...
直到即将执行命令并首先处理参数的所有扩展以构建此可执行行之前:
$ IFS=. printf "%s\n" a.b.c ## IFS=. goes to the environment.
a.b.c
在为命令提供参数和之前$var
,使用“旧” IFS将的值扩展为。a.b.c
printf
"%s\n"
a.b.c
可以通过以下方式引入一种延迟级别eval
:
$ IFS=. eval printf "'%s\n'" \$var
a
b
c
该行将被解析(第一次),并显示“ IFS =”。设置为以下环境:
$ printf '%s\n' $var
然后它再次解析为:
$ printf '%s\n' a b c
并执行到此:
a
b
c
的值$var
(ABC)是分裂与IFS的使用中的值:.
。
复杂而棘手的部分是在环境中什么时候有效!
吉尔斯答案的第一部分对此进行了很好的解释。
带有其他细节。
执行此命令时:
$ IFS=. arr=($var)
IFS的价值保留在当前环境中,是的:
$ printf '<%s> ' "${arr[@]}" "$IFS"
<a> <b> <c> <.>
但这是可以避免的:为单个语句设置IFS
$ IFS=. command eval arr\=\(\$var\)
$ printf '<%s> ' "${arr[@]}" "$IFS"
<a> <b> <c> <
>
IFS
设置为.
“ Eek。在阅读了第一部分之后,这是有道理的,但是在我发布此问题之前,我不会期望如此。