为什么我不能为一次printf调用设置IFS

时间:2014-08-06 06:27:51

标签: bash

考虑这行代码,其中deps包含依赖项列表:

IFS=',' printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"

我将IFS设置为,,用于单次调用printf,但奇怪printf似乎不尊重IFS,因为它不会展开deps以逗号分隔的列表。

另一方面,如果我像这样设置IFS:

IFS=','
printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"

printf正确地将deps扩展为以逗号分隔的列表。

我在这里想念一下吗?

2 个答案:

答案 0 :(得分:6)

在此命令行中:

IFS=',' printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"

printf不展开"${deps[*]}"。 shell进行扩展。事实上,这总是如此。尽管printf碰巧是shell内置的,但它对其参数没有做任何特殊处理,并且您将获得与外部printf完全相同的行为。

语法

envvar=value program arg1 arg2 arg3

导致shell将envvar=value添加到提供给program的环境变量列表中,并将字符串arg1arg2arg3添加到制作成program的argv列表。在所有这些发生之前,shell会执行各种类型的正常扩展,这将导致value中引用的shell变量和三个参数被替换为它们的值。但是环境变量设置envvar=value不是shell执行环境的一部分。

同样地,

FOO=World echo "Hello, $FOO"
FOO=World的参数中展开$FOO时,

不会使用echo"Hello, $FOO"由shell的执行环境中的shell扩展,然后作为参数传递给echoFOO=World作为其环境的一部分传递给echo。 / p>

将变量设置放在单独的命令中是完全不同的。

IFS=','; printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"
在shell解析IFS命令之前,

首先在 shell的环境中设置printf的值。当shell在参数中进行扩展时,它最终会传递给printf,它使用IFS的值来扩展数组deps[*]。在这种情况下,IFS 包含在传递给printf的环境变量中,除非先前已导出IFS

使用内置IFS read的{​​{1}}可能会让人感到困惑,但它与上述内容完全一致。在命令

IFS=, read A B C

IFS=,作为环境变量列表的一部分传递给readread消耗一行输入,并在其环境中查询IFS的值,以便弄清楚如何将输入行拆分为单词。

为了在参数中进行参数扩展而更改IFS,必须在shell的环境中进行更改,这是一个全局更改。由于您很少想要全局更改IFS的值,因此常见的习惯用法是在使用()创建的子shell中更改它:

( IFS=,; printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"; )

可能会做你想要的。

答案 1 :(得分:0)

你可以。只需保存它,使用它并重置它:

oldifs=$IFS
IFS=','
printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"
IFS=$oldifs

现在为您的命令,您可以通过在命令之间放置;来在一行上执行此操作:

IFS=','; printf "setup-x86.exe -q -p='%s'\n" "${deps[*]}"

您仍然需要保存并恢复IFS

您可以将IFS设置为一次性交易的唯一地方是while循环。 E.g:

while IFS=$'\n' read line; do
....
done

在这种情况下,它只是在while循环中应用。