PassingVariables

Last edit

Changed:

< === shells
< the examples using quoting are intended for use with any standard
< (sh-compatible-quoting) Unix shell. as with all complex quoting,
< all these examples become much easier to work with (or under DOS
< and MS-Windows, less impossible) when put in a file and invoked with
< `awk -f filename.
awk' instead.
< non-sh-compatible shells will require different quoting
. if you're
< not even using Unix (or a ported Unix shell), just ignore the whole
< section on quoting
.

to

> === Shells
> <include "Shells">
> [[http://
awk.freeshell.org/?action=edit;id=Shells| Edit this answer]]

Changed:

< **Answer 1:**
<
< On Unix, use
"alternate quoting", e.g.
< {{{
< awk -F: '$1 ~ /'"$USER"'/ {print $5}' /etc/passwd
< ^^^^^^^^*******^^^^^^^^^^^^^^
< }}}
< Any standard Unix shell will send the underlined part as one
< long argument (with embedded spaces) to awk, for instance:
< {{{
< $1 ~ /bwk/ {print $5}
< }}}
< Note that there may not be any spaces between the quoted
< parts. Otherwise, you wouldn't end up a single, long script
< argument, because Unix shells break arguments on spaces
< (unless they are `escaped' with `\', or in '' or "", as the
< above example shows).
< **Answer 2:**
<
< RTFM to see if and how your awk supports variable definitions on the command line, e.g.,
< {{{
< awk -F: -v name="$USER" '$1 ~ name {print $5}' /etc/passwd
< }}}
< **Answer 3**
< RTFM if your
awk can access enviroment vars. Then perhaps
< {{{
< awk -F: '$1 ~ ENVIRON["USER"] {print $5}' /etc/passwd
< }}}
<
<
< Always remember for your /bin/sh scripts that it's easy to put
< things into the environment for a single command run:
< {{{
< name
=felix age=56 awk '... ENVIRON["name"] .....'
< }}}

< this also works with ksh and some other shells.
< The first approach is extremely portable, but doesn't work with
< awk "-f" script files. In that case, it's better to use a shell
< script and stretch a long awk command argument in '...' across
< multiple lines if need be.
< Also note: /bin/csh requires a \ before an embedded newline, /bin/sh not.

to

> <include "EnvVarGeneral">
> [[http://
awk.freeshell.org/?action=edit;id=EnvVarGeneral| Edit this answer]]

Changed:

< Quoting can be such a headache for the novice, in shell programming,
< and especially in awk.
< Art Povelones posted a long tutorial on shell quoting on 1999/09/30
< which is probably too much detail to repeat with the FAQ; if you
< could use it, search via
<http://groups.google.com/>.
< Tim Maher offered his <
http://www.consultix-inc.com/quoting.txt>.
< This approach is probably the best, and easiest to understand and
< maintain, for most purposes: (the '@@' is quoted to ensure the
< shell will copy verbatim, not interpreting environment variable
< substitutions etc.)
< {{{
< cat <<'@@' > /tmp/never$$.awk
< { print "Never say can't." }
< @@
< awk -f /tmp/never$$.awk; rm /tmp/never$$.awk
< }}}
< If you enjoy testing your shell's quoting behavior frequently, you
< could try these:
< {{{
< (see below for a verbose explanation of the first one, with 7 quotes)
< awk 'BEGIN { q="'"'"'";print "Never say can"q"t."; exit }'
< nawk -v q="'" 'BEGIN { print "Never say can"q"t."; exit }'
< awk 'BEGIN { q
=sprintf("%c",39); print "Never say can"q"t."; exit }'
< awk 'BEGIN { q
=sprintf("%c",39); print "Never say \"can"q"t.\""; exit }'
< }}}
< However, you would also have to know why you could not use this:
< {{{
< awk 'BEGIN { q="\'"; print "Never say \"can"q"t.\""; exit }'
< }}}
< explanation of the 7-quote example:
< note that it is quoted three different ways:
< {{{
< awk 'BEGIN { q="'
< "'"
< '";print "Never say can"q"t."; exit }'
< }}}
< and that argument comes out as the single string (with embedded spaces)
< {{{
< BEGIN { q="'";print "Never say can"q"t."; exit }
< }}}
< which is the same as
< {{{
< BEGIN { q="'"; print "Never say can" q "t."; exit }
< ^^^^^^^^^^^^^ ^ ^^
< |
| | ||
< | | | ||
< vvvvvvvvvvvvv | ||
< Never say can v ||
< ' vv
< t.
< }}}
< which, quite possibly with too much effort to be worth it, gets you
< {{{
< Never say can't.
< }}}

to

> <include "ShellQuoting">
> [[http://awk.freeshell.org/?action=edit;id=ShellQuoting| Edit this answer]]

Changed:

< Modern versions of new awk (gawk, mawk, Bell Labs awk, any POSIX
< awk) all provide an array named ENVIRON. The array is indexed by
< environment variable name
; the value is that variable's value.
< For instance, ENVIRON["HOME"] might be "/home/chris". To print
< out all the names and values, use a simple loop:
< {{{
< for (i in ENVIRON)
< printf("ENVIRON['%s'] = '%s'\n", i, ENVIRON[i])
< }}}
< What if my awk doesn't have
ENVIRON[]?
< Short answer, get a better
awk. There are many freely available
< versions
.
< Longer answer, on Unix you can use a pipe from the `env' or
< `printenv' commands, but this is less pretty, and may be a
< problem if the values contain newlines:
< {{{
< # test this on your system before you depend on it!
< while ( ("env" | getline line) >0 )
< {
< varname
=line
< varvalue
=line
< sub(/=.*$/,"",varname)
< sub(/^[^=]*=/,"",varvalue)
< print "var [" varname "]='" varvalue "'"
< }
< }}}

to

> <include "ENVIRON">
> [[http://
awk.freeshell.org/?action=edit;id=ENVIRON| Edit this answer]]

Changed:

< How can I put values into the environment of the program that
< called my awk program?
< Short answer, you can't. Unix ain't Plan 9, and you can't tweak
< the parent's address space.
< (DOS isn't even Unix, so it lets any program overwrite any memory
< location, including the parent's environment space. But the
< details are [obviously] going to be fairly icky. Avoid.)
< Longer answer, write the results in a form the shell can parse
< to a temporary file, and have the shell "source" the file after
< running the awk program:
< {{{
< awk 'BEGIN { printf("NEWVAR='%s'\n", somevalue) }'
> /tmp/awk.$$
< . /tmp/awk.$$ # sh/ksh/bash/pdksh/zsh etc
< rm /tmp/awk.$$
< }}}
< With many shells, you can use `eval', but
this is also cumbersome:
< {{{
< eval `awk 'BEGIN { print "NEWVAR=" somevalue }'`
< }}}
< Csh syntax and more robust use of quotation marks are left as
< exercises for the reader.

to

> <include "PassingVariablesToTheParentProcess">
> [[http://awk.freeshell.org/?action=edit;id=PassingVariablesToTheParentProcess| Edit this answer]]


Shells

The examples using quoting are intended for use with any standard (sh-compatible-quoting) Unix shell. As with all complex quoting, all these examples become much easier to work with (or under DOS and MS-Windows, less impossible) when put in a file and invoked with `awk -f filename.awk' instead.

Non-sh-compatible shells will require different quoting. If you're not even using Unix (or a ported Unix shell), just ignore the whole section on quoting.

Edit this answer

Environment variables in general

Answer 1:

On Unix, use "alternate quoting", e.g.

        awk -F: '$1 ~ /'"$USER"'/ {print $5}' /etc/passwd
                ^^^^^^^^*******^^^^^^^^^^^^^^

Any standard Unix shell will send the underlined part as one long argument (with embedded spaces) to awk, for instance:

        $1 ~ /bwk/ {print $5}

Note that there may not be any spaces between the quoted parts. Otherwise, you wouldn't end up a single, long script argument, because Unix shells break arguments on spaces (unless they are `escaped' with `\', or in '' or "", as the above example shows).

This approach should be avoided in general, unless it is the only one supported by your version of awk (which, in that case, should be upgraded anyway, and not just for this reason). The problem is that it cannot be trusted to work in general, and the outcomes are highly dependent on the actual content of the shell variables you are using. Some examples follow (taken from discussions on comp.lang.awk):

$ var="#"
$ awk 'BEGIN{ print '"$var"' }'
awk: cmd. line:1: BEGIN{ print # }
awk: cmd. line:1:              ^ syntax error

The above can be "corrected" by using double quotes in the awk program:

$ var="#"
$ awk 'BEGIN{ print "'"$var"'" }'
#

However, there are cases where even that is not enough:

$ var="hello
world"
$ awk 'BEGIN{ print "'"$var"'" }'
awk: BEGIN{ print "hello
awk:              ^ unterminated string

That however works using -v:

$ var="hello
world"
$ awk -v var="$var" 'BEGIN{ print var }'
hello
world 

See next answer for a description of -v:

Answer 2:

RTFM to see if and how your awk supports variable definitions on the command line, e.g.,

  awk -F: -v name="$USER" '$1 ~ name {print $5}' /etc/passwd

Answer 3

RTFM if your awk can access enviroment vars. Then perhaps

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

Always remember for your /bin/sh scripts that it's easy to put things into the environment for a single command run:

        name=felix age=56 awk '... ENVIRON["name"] .....'

this also works with ksh and some other shells.

The first approach is extremely portable, but doesn't work with awk "-f" script files. In that case, it's better to use a shell script and stretch a long awk command argument in '...' across multiple lines if need be.

Also note: /bin/csh requires a \ before an embedded newline, /bin/sh not.

See [1] for a very complete discussion of passing shell variables values to awk programs.

Edit this answer

Unix Shell Quoting

Quoting can be such a headache for the novice, in shell programming, and especially in awk.

Art Povelones posted a long tutorial on shell quoting on 1999/09/30 which is probably too much detail to repeat with the FAQ; if you could use it, search via <http://groups.google.com/>.

Tim Maher offered his <http://www.consultix-inc.com/quoting.txt>.

This approach is probably the best, and easiest to understand and maintain, for most purposes: (the '@@' is quoted to ensure the shell will copy verbatim, not interpreting environment variable substitutions etc.)

    cat <<'@@' > /tmp/never$$.awk
    { print "Never say can't." }
    @@
    awk -f /tmp/never$$.awk; rm /tmp/never$$.awk

If you enjoy testing your shell's quoting behavior frequently, you could try these:

   (see below for a verbose explanation of the first one, with 7 quotes)

    awk 'BEGIN { q="'"'"'";print "Never say can"q"t."; exit }'
    nawk -v q="'" 'BEGIN { print "Never say can"q"t."; exit }'
    awk 'BEGIN { q=sprintf("%c",39); print "Never say can"q"t."; exit }'
    awk 'BEGIN { q=sprintf("%c",39); print "Never say \"can"q"t.\""; exit }'

However, you would also have to know why you could not use this:

    awk 'BEGIN { q="\'"; print "Never say \"can"q"t.\""; exit }'

explanation of the 7-quote example:

note that it is quoted three different ways:

    awk 'BEGIN { q="'
                     "'"
                        '";print "Never say can"q"t."; exit }'

and that argument comes out as the single string (with embedded spaces)

    BEGIN { q="'";print "Never say can"q"t."; exit }

which is the same as

    BEGIN { q="'"; print "Never say can" q "t."; exit }
                          ^^^^^^^^^^^^^  ^  ^^
                          |           |  |  ||
                          |           |  |  ||
                          vvvvvvvvvvvvv  |  ||
                          Never say can  v  ||
                                         '  vv
                                            t.

which, quite possibly with too much effort to be worth it, gets you

                          Never say can't.

Edit this answer

ENVIRON[] and "env"|getline

Modern versions of new awk (gawk, mawk, Bell Labs awk, any POSIX awk) all provide an array named ENVIRON. The array is indexed by environment variable name; the value is that variable's value. For instance, ENVIRON["HOME"] might be "/home/chris". To print out all the names and values, use a simple loop:

        for (i in ENVIRON)
                printf("ENVIRON['%s'] = '%s'\n", i, ENVIRON[i])

What if my awk doesn't have ENVIRON[]?

Short answer, get a better awk. There are many freely available versions.

Longer answer, on Unix you can use a pipe from the `env' or `printenv' commands, but this is less pretty, and may be a problem if the values contain newlines:

        # test this on your system before you depend on it!
        while ( ("env" | getline line) >0 )
        {
                varname=line
                varvalue=line
                sub(/=.*$/,"",varname)
                sub(/^[^=]*=/,"",varvalue)
                print "var [" varname "]='" varvalue "'"
        }

Edit this answer

exporting environment variables back to the parent process

How can I put values into the environment of the program that called my awk program?

Short answer, you can't. Unix ain't Plan 9, and you can't tweak the parent's address space.

(DOS isn't even Unix, so it lets any program overwrite any memory location, including the parent's environment space. But the details are [obviously] going to be fairly icky. Avoid.)

Longer answer, write the results in a form the shell can parse to a temporary file, and have the shell "source" the file after running the awk program:

        awk 'BEGIN { printf("NEWVAR='%s'\n", somevalue) }' > /tmp/awk.$$
        . /tmp/awk.$$        # sh/ksh/bash/pdksh/zsh etc
        rm /tmp/awk.$$

With many shells, you can use `eval', but this is also cumbersome:

        eval `awk 'BEGIN { print "NEWVAR=" somevalue }'`

Csh syntax and more robust use of quotation marks are left as exercises for the reader.

Edit this answer