System calls, AWK, and Bringing in external inputs

6,671

awk can access environment variables using the ENVIRON special array. However, while you can assign values to elements of that array, it is not passed in the environment of the commands executed by awk's system, | getline or print |. That ENVIRON array is only intended for awk to get the value of the environment variables it is passed.

You can do: system("ls " var), but beware that the string that is passed to awk's system() (or print | or | getline) is actually passed as an argument to sh -c, so it is interpreted as shell code.

For instance, if the awk var variable contains foo;rm -rf /, it will not tell ls to list the file called "foo;rm -rf /" but instead to list the file called foo and then the rm command will be run.

So, you may need to escape all the characters special to the shell in that var variable.

This could be done for instance with:

awk '
  function escape(s) {
    gsub(/'\''/, "&\\\\&&", s)
    return "'\''" s "'\''"
  }
  {
    cmd = "date -d " escape($0) " +%s"
    cmd | getline seconds
    close(cmd)
    print seconds
  }'

While that means running one shell and one date command per line, you might as well do the reading of the file with the shell itself:

while IFS= read <&3 -r line; do
  date -d "$line" +%s
done 3< the-file
Share:
6,671

Related videos on Youtube

David Kegyes
Author by

David Kegyes

Personal Website: http://stevenkhicks.de

Updated on September 18, 2022

Comments

  • David Kegyes
    David Kegyes almost 2 years
    awk '{ TEMPVAR="/usr/bin"; printf("%s", system("ls $TEMPVAR")); }' empty
    

    In this example I'm trying to bring in the variable TEMPVAR into the system call. How would I do this?

    What I'm aiming to do: I'm trying to use date -d $0 +%s in a system call that occurs every line of a file. However, I'm struggling with how to get that $0 value into the system call.

  • Lekensteyn
    Lekensteyn over 10 years
    For future readers that wonder why so many quotes and backslashes are used, this is because the snippet is a **shell command too. What you basically need to do is to put single quotes around the argument and substitute the single quotes in the argument by '\'' (end string, insert \', continue string). In an AWK script (file), it is sufficient to use gsub(/'/, "'\\''", s); return "'" s "'";, but for a "one-liner" command, the single quotes and backslashes must be escaped again as shown by Stephane.