为 for 循环设置 IFS 然后在 for 循环内取消设置是否安全?
Is it safe to set IFS for a for loop and then unset it inside the for loop?
考虑以下 shell 脚本,我打算 运行 在任何 POSIX.1-2004 符合者 shell.
log()
{
echo debug: "$*"
}
A=foo:bar:baz
IFS=:
for i in $A
do
log token ">> >>" "$i"
done
unset IFS
# Do more stuff here
我想遍历以冒号分隔的值。在循环中,我想调用一个日志函数,它应该能够完整地回显传递给它的所有参数,并在每个参数中保留多个空格。当我 运行 这段代码时,这是我得到的输出。
debug: token:>> >>:foo
debug: token:>> >>:bar
debug: token:>> >>:baz
好在">> >>"
中的两个空格因为"$*"
的使用而被保留,即引用了[=51的Section 2.5.2 Special Parameters中定义的特殊参数星号=].1-2004.
但不好的是,由于相同的用法,传递给 log
的三个参数现在用冒号分隔(IFS
)。
我通过在 for
循环中 unset
设置 IFS
来解决这个问题。
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
现在,输出如我所愿。
debug: token >> >> foo
debug: token >> >> bar
debug: token >> >> baz
但我想知道是否有可能在某些 POSIX shell 中,在 for
循环中取消设置 IFS
会产生修改的副作用for
循环的 IFS
正在进行中?
例如,我担心某些 POSIX shell 可能会为我的第二个代码示例生成以下输出。
debug: token >> >> foo
debug: token >> >> bar:baz
有人可以通过引用 POSIX.1-2004 中的相关部分来告诉我我的第二个代码示例是否安全,并且是否保证在所有 POSIX 兼容 shells?
如果我的第二个代码示例不安全,那么我可能不得不接受这样的不修改 IFS
.
log()
{
echo debug: "$*"
}
A=foo:bar:baz
echo "$A" | tr : "\n" | while read i
do
log token ">> >>" "$i"
done
很安全。
$A
变量在for循环开始执行前会展开一次:
for i in foo bar baz
一旦发生这种情况,对 IFS 的任何更改都将无效。
参考文献:
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
如果您使用 IFS 只是为了解析该字符串,您可以这样做:
oldIFS=$IFS IFS=:
set -- $A # save the elements of the list as positional parameters
IFS=$oldIFS
for i; do
log "$i"
done
考虑以下 shell 脚本,我打算 运行 在任何 POSIX.1-2004 符合者 shell.
log()
{
echo debug: "$*"
}
A=foo:bar:baz
IFS=:
for i in $A
do
log token ">> >>" "$i"
done
unset IFS
# Do more stuff here
我想遍历以冒号分隔的值。在循环中,我想调用一个日志函数,它应该能够完整地回显传递给它的所有参数,并在每个参数中保留多个空格。当我 运行 这段代码时,这是我得到的输出。
debug: token:>> >>:foo
debug: token:>> >>:bar
debug: token:>> >>:baz
好在">> >>"
中的两个空格因为"$*"
的使用而被保留,即引用了[=51的Section 2.5.2 Special Parameters中定义的特殊参数星号=].1-2004.
但不好的是,由于相同的用法,传递给 log
的三个参数现在用冒号分隔(IFS
)。
我通过在 for
循环中 unset
设置 IFS
来解决这个问题。
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
现在,输出如我所愿。
debug: token >> >> foo
debug: token >> >> bar
debug: token >> >> baz
但我想知道是否有可能在某些 POSIX shell 中,在 for
循环中取消设置 IFS
会产生修改的副作用for
循环的 IFS
正在进行中?
例如,我担心某些 POSIX shell 可能会为我的第二个代码示例生成以下输出。
debug: token >> >> foo
debug: token >> >> bar:baz
有人可以通过引用 POSIX.1-2004 中的相关部分来告诉我我的第二个代码示例是否安全,并且是否保证在所有 POSIX 兼容 shells?
如果我的第二个代码示例不安全,那么我可能不得不接受这样的不修改 IFS
.
log()
{
echo debug: "$*"
}
A=foo:bar:baz
echo "$A" | tr : "\n" | while read i
do
log token ">> >>" "$i"
done
很安全。
$A
变量在for循环开始执行前会展开一次:
for i in foo bar baz
一旦发生这种情况,对 IFS 的任何更改都将无效。
参考文献:
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
如果您使用 IFS 只是为了解析该字符串,您可以这样做:
oldIFS=$IFS IFS=:
set -- $A # save the elements of the list as positional parameters
IFS=$oldIFS
for i; do
log "$i"
done