Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increment a shell variable in an awk action

My shell script is something like this:

#!/bin/bash

global_var=0

func() {
 awk '$1 ~/^pattern/ {global_var=$((global_var+1))}' $1
}

func input_file_name

I want to increment the global (shell) variable global_var inside the awk action. How to do so? Normal shell style incrementing does not seem to be working.

like image 393
user1465266 Avatar asked Sep 17 '25 09:09

user1465266


1 Answers

Try this:

func() {
 awk '$1~/^pattern/ {++awk_var} END {print awk_var+0}' "$1"
}

shell_var=$(func input_file_name)

The shell and awk are separate worlds, and you should treat them as such(*) (which, in effect, you're already doing, by enclosing your awk program in single quotes, which prevents the shell from expanding any shell variable references in your akw program string).

Thus, use an awk[-internal] variable to perform your counting (awk_var) and output it after having finished processing the input file (in the END block, using print to output the awk variable to stdout - the +0 part is to ensure that the output defaults to 0 in case NO match was found.)

Note that, generally, awk variables need no explicit initialization, because they default to 0 in numerical and Boolean contexts, and to "" (empty string) in string contexts).

Also note that awk has its own syntax, and shell constructs such as $((...)) for arithmetic expansion do not apply. Generally, awk variables are referred to just by name (no $ prefix), and arithmetic operations such as ++ can be applied directly.

Using command substitution - $(...) - in the shell then allows you to capture output from the awk command.

In your specific case you have no need to pass variable values into the awk program, but if you needed to do that, you'd use one or more instances of awk's -v option; e.g.: awk -v awk_var="$shell_var" ...

On the shell (bash) side, if you wanted to add awk's output to the shell variable instead of just assigning it:

declare -i shell_var                # make sure variable is an integer
shell_var+=$(func input_file_name)  # add function's output to existing value

(*) The shell and awk have completely separate namespaces that have no direct way of interacting with one another: awk has no concept of shell variables, and the shell has no concept of awk variables.

It is technically feasible, but ill-advised to integrate shell variable VALUES into an awk program - by using a double-quoted string to represent the awk program in which you reference shell variable VALUES, which are then expanded by the shell ONCE, BEFORE the string gets passed as a program to awk.
What you CANNOT do is to modify a shell variable from inside an awk program.

Since it gets complicated quickly as to which parts of the awk program are interpreted by the shell up front vs. which parts are interpreted by awk later (where '$ has special meaning too, for instance), the best approach is to:

  • use a single-quoted string to represent the awk program, so as to protect it from interpretation by the shell
  • if values need to be passed in, use instances of the -v option
  • if something needs to be passed out, print to stdout from awk and use command substitution or redirection to capture it via the shell.
like image 63
mklement0 Avatar answered Sep 18 '25 23:09

mklement0