Ankh2054
Ankh2054

Reputation: 1153

How do I use environment variables in Awk

I've got the following AWK script I'm using to update settings.py. I utilising during Docker install and I'm trying to pass ENV variables.

ENV variables to pass:

DB_USER,
DB_PASS,
DB_NAME

The code below

awk 'function pr(sp, k, v){    # prints key-value pair with indentation
         printf "%s\047%s\047: \047%s\047,\n",sp,k,v; 
     }
     /sqlite/{ sub(/sqlite[0-9]*/,"mysql",$0) }
     /NAME/{ sp=substr($0,1,index($0,"\047")-1); 
             print sp$1" \047$DB_NAME\047"; 
             pr(sp,"USER","$DB_USER"); pr(sp,"PASSWORD","$DB_PASS"); 
             pr(sp,"HOST","localhost"); pr(sp,"PORT",""); next 
     }1'

Upvotes: 9

Views: 8470

Answers (2)

Inian
Inian

Reputation: 85800

You can use the ENVIRON variable in GNU Awk,

From the GNU Awk man page,

ENVIRON

An associative array containing the values of the environment. The array indices are the environment variable names; the elements are the values of the particular environment variables. For example, ENVIRON["HOME"] might be "/home/arnold". Changing this array does not affect the environment passed on to any programs that awk may spawn via redirection or the system() function. (In a future version of gawk, it may do so.)

Using the above array to reference your environment variables, just do this in the BEGIN clause to load all the variables and use it later

awk 'BEGIN {
    db_user = ENVIRON["DB_USER"]
    db_pass = ENVIRON["DB_PASS"]
    db_name = ENVIRON["DB_NAME"]
 }'

Use the variables db_user, db_pass and db_name in the body of the Awk as you wish. By importing the environment variables in BEGIN, you don't have to import them once for each line in the input file.

Upvotes: 13

nickl-
nickl-

Reputation: 8741

There are actually two more ways, aside from ENVIRON, to get shell variables into awk programs, according to the documentation. This is especially useful when using local shell variables as ENVIRON works only for exported or environment variables.

There is a gotcha when trying to use variables as patterns so I will use them as patterns in our examples.

So lets say we want to get the current user's home directory from /etc/passwd, the separator is : so we need to tell awk about that by using the -F argument.

Without using variables we would write the simple program like this:

$ awk -F: '$1~/nickl/ {print $6}' /etc/passwd
/home/nickl

But instead we want to use the environment variable $USER.

Method 1. using shell string quote substitution

We can separate the awk program string by supplying both single and double quoted strings without spaces in between, the latter will of course allow for variable substitution where as the former ignores the $ used by awk to denote field numbers.

$ awk -F: '$1~'"/$USER/ "'{print $6}' /etc/passwd
/home/nickl

Method 2. using command line variables

The previous method could get confusing and land you into trouble trying to keep track of separated strings, especially with more complex programs, so instead we can use command line variable assignment with the -v option.

$ awk -F: -v var=$USER '$1~var {print $6}' /etc/passwd
/home/nickl

Note: You would probably want to put the variable into quotes "$USER" if there is any chance that it might contain spaces.

Method 3. using the built-in variable

As per the accepted answer, the third option is to use the built-in variable ENVIRON. You may have noticed from the previous method that we are not using regexp constant, by excluding the slashes // from the pattern. The gotcha is when using awk variables in patterns we use dynamic regexps instead, without the slashes.

$ awk -F: '$1~ENVIRON["USER"] {print $6}' /etc/passwd
/home/nickl

EDIT: As pointed out by @RAREKpopManifesto, if directly declared we can pass local variables to be accessible by ENVIRON, even without changing an exported variable.

$ LOCAL_USER="rarek"
$ USER="$LOCAL_USER" awk -F: '$1~ENVIRON["USER"] {print $6}' /etc/passwd
/home/rarek
$ echo $USER
nickl

nJoy!

Upvotes: 2

Related Questions