10

第一次在这里发帖,但多年来一直是潜伏者。我已经用谷歌搜索了很长时间,但找不到我想要的东西(许多不要求该主题暗示它的主题的大主题......)。对 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 中设置 env 变量,以便在 awk 执行完成后调用进程可以访问这些 env 值?真的有可能吗?

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

欢迎所有想法/建议/评论!

4

4 回答 4

8

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

MYSCRIPT_RESULT=$(awk stuff)

是不可接受的,您所要求的无法完成。

于 2012-08-16T14:06:30.547 回答
3

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

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

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

于 2012-08-16T16:13:27.930 回答
3

您还可以使用 awk 中在当前 shell 中设置变量中描述的内容

 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。

于 2015-11-17T12:06:23.210 回答
-1

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

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

例1:

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

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

例 2:

#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 个变量:Datawith valuesda6Archwith value sda7

一行中的相同示例。

$(lsblk -o NAME,LABEL | awk 'BEGIN{txt="declare "}/Data|Arch/{txt=txt$2"="substr($1,3)" "}END{print txt}')
于 2020-01-02T04:51:55.140 回答