AWK: return value to shell script
Asked Answered
S

5

19

Is it possible to have an awk command within a bash script return values to a bash variable, i.e.,if my awk script does some arithmetic operations, can I store the answers in variables so, they can be accessed in the bash script. If possible, how to distinguish between multiple return variables. Thanks.

Stopple answered 14/3, 2012 at 18:36 Comment(0)
R
22

No. You can use exit to return an error code, but in general you can't modify the shell environment from a subprocess.

You can also, of course, print the desired content in awk and put it into variables in bash by using read:

read a b c <<< $(echo "foo" | awk '{ print $1; print $1; print $1 }')

Now $a, $b and $c are all 'foo'. Note that you have to use the <<<$() syntax to get read to work. If you use a pipeline of any sort a subprocess is created too and the environment read creates the variables in is lost when the pipeline is done executing.

Renunciation answered 14/3, 2012 at 18:40 Comment(9)
how? can you give an example please. ThanksStopple
@ShuvoShams: I added one, hope it helps.Renunciation
@EduardoIvanec - modifying a parent process' environment (variables) is so difficult that it might as well be declared "near impossible".Unbelievable
@AndrewBeals: do you have a link to one of the difficult ways? I know you can pass a pointer to the current environment in some low level Unix syscalls, but I don't know of any way to do this in the shell level.Renunciation
@EduardoIvanec Actually, the last time I wanted to do something like that, it involved digging in the process table to find where the parent was located, then mucking about in /dev/mem directly. You can't get access to your parent's address space unless you're root and you dig about in the system's memory space, or if the parent explicitly shares it with you via the shared memory syscalls — and at that point, you might as well declare some sort of interface and pass the information around with proper IPC calls.Unbelievable
+1 Another technique is to have the awk script output bash commands that you can source: source <(awk '{...processing...} END {print "a=" a_val ";b=" b_val ";c=" c_val}')Veracity
Thanks Glenn, but, getting error messages while executing. I have two variables, one updating the input file (if condition is met) as each record is updated and other keeping a counter. Currently, my redirection is not working right either. Here is the code: source <(awk '{BEGIN {ct=0}{if($1 < 100) ct++ else if ($3 > 100) $3=sprintf("%.1f",$3/100);print $1"\t"$2"\t"$3;} END{print ct}' $f_name > tmp.stat && mv tmp.stat $f_name . Will very much appreciate some pointersStopple
I had to change the command to read -d '' a b c <<< $(echo "foo" | awk '{ print $1; print $1; print $1 }') to make it work.Ingunna
@glennjackman Under bash, you could use coproc for doing this repetitively by using only 1 fork to awkGardol
S
8
var=$(awk '{ print $1}')

This should set var to the output of awk. Then you can use string functions or whatever from there to differentiate within the value or have awk print only the part you want.

Swartz answered 22/8, 2018 at 19:29 Comment(3)
This to me is the simplest answer and worked for what I was trying to do.Chaddie
This code is taken from context and does not work as single line. Better to replace it something like: result=$(awk 'BEGIN { print "result from awk" }'); echo $resultIngratiating
@SheldonJuncker : make that var=$( awk NF=1 ) - that statement is shell safe to be left unquoted, cuz although it looks like a command line assignment for awk, in the absence of anything else, that statement becomes the main "pattern"Deltadeltaic
S
1

I know this question is old, but there's another way to do this that's worked really well for me, and that's using an unused file descriptor. We all know stdin (&0), stdout (&1), and stderr (&2), but as long as you redirect it (aka: use it), there's no reason you can't use fd3 (&3).

The advantage to this method over other answers is that your awk script can still write to stdout like normal, but you also get the result variables in bash.

In your awk script, at the end, do something like this:

END {
  # print the state to fd3
  printf "SUM=%s;COUNT=%s\n", tot, cnt | "cat 1>&3"
}

Then, in your bash script, you can do something like this:

awk -f myscript.awk <mydata.txt 3>myresult.sh
source myresult.sh
echo "SUM=${SUM} COUNT=${COUNT}"
Sepulchre answered 23/8, 2022 at 22:31 Comment(0)
I
0

To get single string result from awk in bash Command substitution $() can be used:

result=$(awk 'BEGIN { print "result from awk" }'); echo $result

Equivalent example:

result=$(awk '{print}' <<< "result from awk"); echo $result
Ingratiating answered 7/6 at 18:9 Comment(0)
G
0

my awk script does some arithmetic operations

If you plan to do some arithmetic operations repetitively, you could run awk (or bc, but this work with date, sed, and near every Un*X filters) in background:

coproc AWK {
    exec stdbuf -o0 -i0 awk '{ print sqrt($1), $1^2, 4*atan2($1,1); }'
}
awkPid=$!
ps $awkPid
    PID TTY      STAT   TIME COMMAND
  85915 pts/3   S      0:00 awk { print sqrt($1), $1^2, 4*atan2($1,1); }
echo >&${AWK[1]} 25
read -ru ${AWK[0]} line
echo $line
5 625 6.12327
for i in {1..10}; do
    echo >&${AWK[1]} $i
    read -ru ${AWK[0]} sqr pow ata
    printf '%3d %7.3f %4d %8.5f\n' $i $sqr $pow $ata
done
  1   1.000    1  3.14159
  2   1.414    4  4.42859
  3   1.732    9  4.99618
  4   2.000   16  5.30327
  5   2.236   25  5.49360
  6   2.449   36  5.62259
  7   2.646   49  5.71560
  8   2.828   64  5.78577
  9   3.000   81  5.84056
 10   3.162  100  5.88451
exec {AWK[0]}<&-
exec {AWK[1]}>&-
[1]+  Done    coproc AWK { exec stdbuf -o0 -i0 awk '{ print sqrt($1), $1^2, 4*atan2($1,1); }'; }
ps $awkPid
    PID TTY      STAT   TIME COMMAND
exit
Gardol answered 15/6 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.