awk: setting environment variables directly from within an awk script

Viewed 16403

first post here, but been a lurker for ages. i have googled for ages, but cant find what i want (many abigious topic subjects which dont request what the topic suggests it does ...). not new to awk or scripting, just a little rusty :)

i'm trying to write an awk script which will set shell env values as it runs - for another bash script to pick up and use later on. i cannot simply use stdout from awk to report this value i want setting (i.e. "export whatever=awk cmd here"), as thats already directed to a 'results file' which the awkscript is creating (plus i have more than one variable to export in the final code anyway).

As an example test script, to demo my issue:

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 

within scriptfile.awk, i have tried (without sucess)

1/) building and executing an adhoc string directly:

{
  cmdline="export MYSCRIPT_RESULT=1"
  cmdline
}

2/) using the system function:

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

... but these do not work. I suspect that these 2 commands are creating a subshell within the shell awk is executing from, and doing what i ask (proven by touching files as a test), but once the "cmd"/system calls have completed, the subshell dies, unfortunatley taking whatever i have set with it - so my env setting changes dont stick from "the caller of awk"'s perspective.

so my question is, how do you actually set env variables within awk directly, so that a calling process can access these env values after awk execution has completed? is it actually possible?

other than the adhoc/system ways above, which i have proven fail for me, i cannot see how this could be done (other than writing these values to a 'random' file somewhere to be picked up and read by the calling script, which imo is a little dirty anyway), hence, help!

all ideas/suggestions/comments welcomed!

4 Answers

I found a good answer. Encapsulate averything in a subshell! The comand declare works as below:

#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}')

I found some really interesting uses for this technique. In the next exemple I have several partitions with labels. I create variables using the labels as variable names and the device name as variable values.

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}'\
)

The end result of this is 2 variables: Data with value sda6 and Arch with value sda7.

The same exemple in a single line.

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