【问题标题】:awk: setting environment variables directly from within an awk scriptawk:直接从 awk 脚本中设置环境变量
【发布时间】:2012-08-12 21:23:09
【问题描述】:

第一次在这里发帖,但多年来一直是潜伏者。我已经用谷歌搜索了很长时间,但找不到我想要的东西(许多不要求该主题暗示它的主题的大主题......)。对 awk 或脚本并不陌生,只是有点生疏:)

我正在尝试编写一个 awk 脚本,该脚本将在运行时设置 shell env 值 - 以便稍后获取另一个 bash 脚本并使用。我不能简单地使用 awk 的标准输出来报告我想要设置的这个值(即“导出任何东西=awk cmd here”),因为那已经指向 awkscript 正在创建的“结果文件”(另外我有多个变量要无论如何导出最终代码)。

作为一个示例测试脚本,来演示我的问题:

echo $MYSCRIPT_RESULT          # returns nothing, not currently set
echo | awk -f scriptfile.awk   # do whatever, setting MYSCRIPT_RESULT as we go
echo $MYSCRIPT_RESULT          # desired: returns the env value set in scriptfile.awk 

在 scriptfile.awk 中,我尝试过(没有成功)

1/) 直接构建和执行临时字符串:

{
  cmdline="export MYSCRIPT_RESULT=1"
  cmdline
}

2/) 使用系统函数:

{
  cmdline="export MYSCRIPT_RESULT=1"
  system(cmdline)
}

...但是这些不起作用。我怀疑这两个命令在 awk 正在执行的 shell 中创建了一个子 shell,并按照我的要求做(通过触摸文件作为测试证明),但是一旦“cmd”/系统调用完成,子 shell 就会死掉,不幸的是使用我设置的任何内容 - 所以我的环境设置更改不会从“awk 的调用者”的角度坚持。

所以我的问题是,您如何在 awk 中直接设置环境变量,以便在 awk 执行完成后调用进程可以访问这些环境值?真的有可能吗?

除了上面的 adhoc/system 方式,我已经证明它对我来说是失败的,我看不到如何做到这一点(除了将这些值写入某个“随机”文件以供调用方获取和读取脚本,反正 imo 有点脏),因此,帮助!

欢迎所有想法/建议/cmets!

【问题讨论】:

  • 不行。这是操作系统环境的基本规则,子进程可以更改它们的环境,但不能更改其父进程的环境。您可以做的最好的事情是(来自 shell 脚本)myParentVar=$( echo "$myParentVar" | awk '{sub(/xxxx/, "yyyy", $0); print $0}' )(其中sub(...) 是您想要对 $myParetntVar 进行的任何修改的占位符。祝您好运。
  • 感谢您的回复。我很害怕会出现这种情况(父/子环境设置和影响范围),所以认为我将不得不为这些环境变量使用临时文件,以便调用 bash 脚本访问。谢谢你确认我的想法:(
  • 我也遇到了这个问题。我所做的是将 awk 输出写入临时文件,然后获取临时文件。作品。不确定它是否优雅但仍然非常单一。

标签: awk


【解决方案1】:

您无法更改父进程的环境。如果

MYSCRIPT_RESULT=$(awk stuff)

是不可接受的,你所要求的不能完成。

【讨论】:

  • 如上所述,您是对的,因为我正在尝试从孩子调整父环境,这是一个禁忌(当我第一次发布时没有这样想)。这留下了 2 种前进的方式:要么让 awk (stdout) 的返回成为你所追求的结果,要么如果那不可能(像我一样)将这些值报告到一个文本文件中,然后父母可以检查该文件以获得这些值您正在尝试回传(在我的情况下,使用 env 变量告诉 awk 这个“更新文件”在哪里(使用 mktemp),使代码/实现中的内容更加简洁:))。
  • 迟来的也建议将变量切换为小写——大写是为系统变量保留的,应该避免用于您的私有变量。
【解决方案2】:

您可以这样做,但这有点麻烦。由于awk 不允许重定向到文件描述符,您可以使用fifo 或常规文件:

$ mkfifo fifo
$ echo MYSCRIPT_RESULT=1 | awk '{ print > "fifo" }' &
$ IFS== read var value < fifo
$ eval export $var=$value

实际上没有必要拆分 var 和 value;您可以轻松地让 awk 打印“导出”并直接评估输出。

【讨论】:

  • gawk 中,您可以输出到在父 shell 中打开的备用文件描述符。作为替代方案,如果 stderr 没有被以其他方式使用,它可以用作输出值的一种方式。
  • fifo 是一个有趣的想法,但是有一种可能性(总是存在)awk 命令可能无法返回任何内容(错误条件),然后阻止执行 fifo 读取(awk 脚本不是一个班轮 - 远非如此!)。我也喜欢使用 stderr 的想法,但是如果/当脚本失败时,stderr 应该保持“没有代码”,因为我们不想在运行时将 gibber 引入程序,因此我认为这不是一个好主意使用任何一个 - 但无论如何都要感谢(我确实说欢迎所有想法) - 我已经使用了临时文件,它只是更安全一点
  • 直到今天我还从未听说过 mkfifo。谢谢! mkfifo + nc = 是的!
【解决方案3】:

你也可以使用类似描述的东西 Set variable in current shell from awk

 unset var
 var=99
 declare $( echo "foobar" | awk '/foo/ {tmp="17"} END {print "var="tmp}' )
 echo "var=$var"
var=

awk END 子句是必不可少的,否则如果模式不匹配,则声明会将当前环境转储到标准输出并且不会更改变量的内容。

可以设置多个值,用空格隔开。

 declare a=1 b=2
 echo -e "a=$a\nb=$b"

注意:declare 仅适用于 bash,对于其他 shell,请使用相同语法的 eval。

【讨论】:

    【解决方案4】:

    我找到了一个很好的答案。将所有内容封装在子外壳中! 该命令声明的工作方式如下:

    #Creates 3 variables
    declare var1=1 var2=2 var3=3
    

    ex1:

    #Exactly the same as above
    $(awk 'BEGIN{var="declare "}{var=var"var1=1 var2=2 var3=3"}END{print var}')
    

    我发现这种技术有一些非常有趣的用途。在下一个示例中,我有几个带有标签的分区。我使用标签作为变量名和设备名作为变量值来创建变量。

    ex2:

    #Partition data
    lsblk -o NAME,LABEL
    
    NAME   LABEL
    sda
    ├─sda1
    ├─sda2
    ├─sda5 System
    ├─sda6 Data
    └─sda7 Arch
    
    #Creates a subshell to execute the text
    $(\
    #Pipe lsblk to awk
    lsblk -o NAME,LABEL | awk \
    #Initiate the variable with the text for the declare command
    'BEGIN{txt="declare "}'\
    #Filters devices with labels Arch or Data
    '/Data|Arch/'\
    #Concatenate txt with itself plus text for the variables(name and value)
    #substr eliminates the special caracters before the device name
    '{txt=txt$2"="substr($1,3)" "}'\
    #AWK prints the text and the subshell execute as a command
    'END{print txt}'\
    )
    

    最终结果是 2 个变量:Data 的值为 sda6Arch 的值为 sda7

    单行中的相同示例。

    $(lsblk -o NAME,LABEL | awk 'BEGIN{txt="declare "}/Data|Arch/{txt=txt$2"="substr($1,3)" "}END{print txt}')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-29
      • 2012-01-19
      • 2016-10-07
      • 1970-01-01
      • 2021-05-27
      • 2013-02-06
      • 2021-03-04
      相关资源
      最近更新 更多