awk:直接在awk脚本中设置环境变量

awk:直接在awk脚本中设置环境变量,awk,Awk,这里是第一个帖子,但多年来一直是个潜伏者。我在谷歌上搜索了很久,但找不到我想要的东西(许多不需要主题建议的主题…)。对awk或脚本编写并不陌生,只是有点生疏:) 我正在尝试编写一个awk脚本,它将在运行时设置shell env值,以供另一个bash脚本在以后使用。我不能简单地使用来自awk的stdout来报告我想要设置的这个值(即“export which=awk cmd here”),因为它已经指向awkscript正在创建的“结果文件”(另外,我还有多个变量要在最终代码中导出) 作为示例测试

这里是第一个帖子,但多年来一直是个潜伏者。我在谷歌上搜索了很久,但找不到我想要的东西(许多不需要主题建议的主题…)。对awk或脚本编写并不陌生,只是有点生疏:)

我正在尝试编写一个awk脚本,它将在运行时设置shell env值,以供另一个bash脚本在以后使用。我不能简单地使用来自awk的stdout来报告我想要设置的这个值(即“export which=
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)
}
。。。但这些都不起作用。我怀疑这两个命令正在shell中创建一个子shell,awk正在从中执行,并按照我的要求执行(通过触摸文件作为测试来证明),但一旦“cmd”/“system”调用完成,子shell就会死亡,不幸的是,我用它设置了任何东西,因此我的环境设置更改不会从“awk的调用者”开始这是我的观点

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

除了上面的特殊/系统方法(我已经证明了这一点)失败之外,我看不出如何做到这一点(除了将这些值写入某个地方的“随机”文件,以便调用脚本拾取和读取,这在imo中有点脏),因此,请帮助


欢迎所有想法/建议/意见

您不能更改父进程的环境。如果

MYSCRIPT_RESULT=$(awk stuff)

这是不可接受的,你所要求的是做不到的。

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

$ mkfifo fifo
$ echo MYSCRIPT_RESULT=1 | awk '{ print > "fifo" }' &
$ IFS== read var value < fifo
$ eval export $var=$value
$mkfifo-fifo
$echo MYSCRIPT_RESULT=1 | awk'{print>“fifo”}'&
$IFS==读取变量值

实际上没有必要拆分var和价值;您可以很容易地让awk打印“导出”并直接评估输出。

您也可以使用中描述的内容

否则,如果模式declare没有匹配项,awk END子句将当前环境转储到stdout,并且不会更改变量的内容,那么awk END子句是必不可少的

可以通过用空格分隔多个值来设置它们

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

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

我找到了一个很好的答案。将所有内容封装在子shell中! 承包商应按照以下要求进行工作和申报:

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

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

例2:

最终结果是两个变量:
Data
带值
sda6
Arch
带值
sda7

同一个例子在一行中

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

不行。这是操作系统环境的基本规则,子进程可以更改其环境,但不能更改其父进程的环境。您所能做的最好的事情是,(从shell脚本中)
myParentVar=$(echo“$myParentVar”| awk'{sub(/xxxx/,“yyyy”,$0);print$0}')
(其中,
sub(…)
是您想要对$myparetvar进行的任何修改的占位符。祝您好运.thx回复成功。我很震惊,这将是这样的情况(父/子环境设置和影响范围),因此我想我必须为这些环境变量准备一个临时文件,以便调用bash脚本访问.thx以确认我的想法:(我也有一个问题。我所做的是将awk输出写入一个临时文件,然后获取临时文件。Works。不确定它是否优雅,但仍然非常unixy。如上所述,你是对的,我正试图从子环境调整父环境,这是一个否定的否定(我第一次发布时没有想到这一点)。这就留下了两种前进的方法:要么返回awk(stdout)您想要的结果,要么如果不可能(像我一样)将这些值报告到一个文本文件中,然后家长可以检查该文本文件以获取您试图传回的值(在我的情况下,使用env变量告诉awk这个“更新文件”在哪里(使用mktemp),使代码/实现更简洁:))。晚些时候还建议将变量切换为小写-大写是为系统变量保留的,并且应该避免为您的专用变量使用。在
gawk
中,您可以输出到父shell中打开的备用文件描述符。或者,如果未以其他方式使用
stderr
,则可以使用fifo是一个有趣的想法,但是有一种可能性(总是存在),即awk命令可能无法返回任何东西(错误条件),这会阻止fifo读取时的执行(awk脚本不是一行代码-远非如此!)。我也喜欢使用stderr的想法,但是应该保留stderr如果/当脚本失败时,“清除代码”,因为我们不想在运行时将gibber引入程序,因此我认为使用这两种方法都不是一个好主意,但无论如何都要感谢这两种方法(我确实说过欢迎所有想法)-我用了tempfiles,只是有点安全,直到今天我才听说过mkfifo。谢谢!mkfifo+nc=是的!
#Exactly the same as above
$(awk 'BEGIN{var="declare "}{var=var"var1=1 var2=2 var3=3"}END{print var}')
#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}'\
)
$(lsblk -o NAME,LABEL | awk 'BEGIN{txt="declare "}/Data|Arch/{txt=txt$2"="substr($1,3)" "}END{print txt}')