在awk代码块中修改一个shell变量

4
有没有办法在awk代码块内修改shell变量?
--------- [shell_awk.sh]---------------------
 #!/bin/bash

shell_variable_1=<value A>
shell_variable_2=<value B>
shell_variable_3=<value C>

awk 'function A(X)
{ return X+1 }
{ a=A('$shell_variable_1')
  b=A('$shell_variable_2')
  c=A('$shell_variable_3')
  shell_variable_1=a
  shell_variable_2=b
  shell_variable_3=c
}' FILE.TXT
--------- [shell_awk.sh]---------------------

这是一个非常简单的例子,实际脚本会加载文件并使用函数进行一些更改。我需要将每个变量在更改之前保存到特定变量中,这样我就可以在MySQL中记录变化前后的值。
更改后的值来自于参数($1、$2等)。
我已经知道如何从文件中获取更改前的值。
所有操作都很顺利,除了awk变量设置的shell_variable。在awk代码块外部很容易设置,但在内部是否可能呢?
1个回答

7

没有任何程序 -- 包括awk、shell或其他语言 -- 可以直接修改父进程的内存。这包括变量。但是,当然,您的awk可以将内容写入标准输出,然后父shell可以读取这些内容并自己修改其变量。


以下是一个将键/值对写出供bash读取的awk示例。它并不完美 -- 请阅读下面的注意事项。

#!/bin/bash

shell_variable_1=10
shell_variable_2=20
shell_variable_3=30

run_awk() {
        awk -v shell_variable_1="$shell_variable_1" \
            -v shell_variable_2="$shell_variable_2" \
            -v shell_variable_3="$shell_variable_3" '
        function A(X) { return X+1 }
        { a=A(shell_variable_1)
          b=A(shell_variable_2)
          c=A(shell_variable_3) }
        END {
          print "shell_variable_1=" a
          print "shell_variable_2=" b
          print "shell_variable_3=" c
        }' <<<""
}

while IFS="=" read -r key value; do
        printf -v "$key" '%s' "$value"
done < <(run_awk)

for var in shell_variable_{1,2,3}; do
  printf 'New value for %s is %s\n' "$var" "${!var}"
done

优点

  • 不使用eval。在awk输出的内容中出现的$(rm -rf ~)等内容不会被shell执行。

缺点

  • 不能处理变量内容中的换行符。(您可以通过NUL字符分隔输出来修复此问题,并将-d''添加到read命令中)。
  • 有恶意的awk脚本可能会修改PATHLD_LIBRARY_PATH或其他安全敏感变量。(您可以通过将变量读入关联数组(而不是全局命名空间)中,或强制对它们的名称添加前缀来修复此问题)。
  • 上面的代码使用了几个ksh扩展,也适用于bash;但是,它将无法在POSIX sh中运行。因此,请确保不要通过sh scriptname运行此代码(这仅保证POSIX功能)。

非常感谢您的答案,我会将其应用到我的脚本中并进行一些测试。尽快完成后,我会返回结果。 - undefined
你的脚本运行得很好,是一个非常不错的模型。不幸的是,我的脚本需要加载一个文件,并且根据列位置(而不是分隔符位置)进行操作。为了实现这个技巧,我需要使用read命令通过文件描述符打开文件,逐行读取,然后结合你的read示例中的printf -v来使用,所有这些都被封装在函数中。我试图做一个简单的示例,但是失败了,而且我的最终脚本受到法律保护,所以我只能解释而没有提供代码。感谢你的帮助。 - undefined
你不应该需要那种变通方法:我在END语句中放置print的整个目的是在完成对任何输入文件的行处理之后才运行它们。当你用输入文件的重定向替换<<<""时,你确实将其删除了吗? - undefined
顺便说一下,如果你最终需要在每行输入时调用awk,我建议你最好在本地的bash中实现处理。请参考http://mywiki.wooledge.org/BashFAQ/100,了解一些可能首先考虑使用`awk`的操作的起步方法。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接