Bash的IFS变量如何影响命令替换?

时间:2013-06-13 00:47:50

标签: bash parsing shell awk command-substitution

我正在编写一个bash脚本,它循环遍历命令替换的输出,然后尝试在循环体内执行另一个命令替换。这是代码:

#!/usr/bin/bash

IFS=$'\n' 

for i in $( xmllint --xpath "string(/*[local-name()='Project'])" gsGDAL/gsGDAL.vcxproj.user )
do
   IFS=' ' #attempted with and without this line
   "$( awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )"
   IFS=$'\n' #attempted with and without this line
done

我将IFS设置为换行符,以便循环遍历xmllint命令的每个输出LINE,而不是迭代每个以空格分隔的单词。 但是,这会使循环内的命令替换失败。一些调试得出结论,问题的实质是:

#!/usr/bin/bash

IFS=$'\n'

$(echo export TEST="test")

给出错误:

./x.sh: line 6: export TEST=test: command not found

通过在循环中重置IFS,您可以看到我尝试在第一个代码示例中进行修复。那没用。

我意识到我可以使用不同的习惯用法来解决问题 例如process将xmllint命令替换为awk,而不是在每条单独的行上执行awk以命名一种可能性。 欢迎提出相关意见,但请提交与以下内容相关的答案:

  1. 为什么将IFS设置为换行符会导致命令替换生成导出?
  2. 为什么在循环中重置IFS不能解决问题?

  3. 更新: 根据与Barmar的讨论,IFS用于命令/变量扩展后的分词。

2 个答案:

答案 0 :(得分:4)

我认为IFS不是导致问题的原因。您的代码存在两个问题:

  1. 您将$(awk ...)放在双引号中,因此不会进行任何分词。因此它将export varname="value"视为命令的名称 - 空格是命令名称的一部分,而不是命令和参数之间的分隔符。

  2. 即使没有双引号,它也不会起作用,因为没有对命令替换的结果执行引用处理,只进行了字拆分和通配符扩展。因此,export命令中的双引号将作为文字字符包含在所分配的值中。

  3. 正如mplf所指出的,解决方法是使用eval

    eval "$(awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )"
    

答案 1 :(得分:2)

使用eval来评估从子shell返回的字符串。

IFS=' ' #attempted with and without this line
eval $( awk -F= '{printf("export %s=\"%s\"", $1, $2)}' <(echo $i) )
IFS=$'\n' #attempted with and without this line