Steve Lorimer
Steve Lorimer

Reputation: 28659

How to pass an awk variable to a bash command

How can I pass an awk variable to a bash command run within awk?

I'm using awk to calculate a running sum of threads for each of a certain process, but then I want to use each pid to access the /proc/$pid filesystem.

The line marked broken below is incorrect, because $pid is non-existent.

How can I export the awk variable pid to the shell command I get awk to run?

(Line breaks added for readability)

$ ps -ALf | grep $PROC | grep -v grep | \         # get each pid
    awk '{threads[$2]+=1} END \                   # count num threads per pid
         { \
           for (pid in threads) \
              "cat /proc/$pid/cwd"|getline cwd; \ # get 'cwd' (**broken**)
               print cwd ": " threads[pid] \      # display 'cwd' and num threads
         }'

Upvotes: 3

Views: 2286

Answers (3)

johnsyweb
johnsyweb

Reputation: 141770

You can do the whole lot in without any greps link this:

% ps -ALf | awk -v proc="${PROC}" '
$0 ~ proc && !/awk/ {
    threads[$2] += 1
}
END {
    for (pid in threads) {
        "readlink /proc/" pid "/cwd" | getline dir
        printf "%d: %d %s\n", pid,  threads[pid], dir
        dir=""
    }
}'

A few things worth noting:

  • -v proc="${PROC}" assigns the environment variable ${PROC} to an awk variable, proc
  • "readlink /proc/" pid "/cwd" concatenates the three strings. There's no need for any concatenation operator in awk.
  • dir="" resets the dir variable, in case the symlink is not readable the next time around the loop.

Upvotes: 2

Thor
Thor

Reputation: 47089

You cannot cat /proc/$pid/cwd it is a symlink to a directory. One way to resolve symlinks is with readlink from coreutils.

Here is a working example using bits from TrueY and Barmer:

ps -C $PROC | 
awk '{ t[$1] } END { for(p in t) { "readlink -f /proc/" p "/cwd" | getline c; print c } }'

A couple of things to notice:

  • Pipe doubles as a line continuation character.
  • It is enough to refer to an array entry to create it (t[$1]).

Upvotes: 4

Barmar
Barmar

Reputation: 780663

awk doesn't do variable interpolation inside strings, you just concatenate the variable with the strings (just like you do in the print statement).

awk '{threads[$2]+=1} END                    # count num threads per pid
     { 
       for (pid in threads) 
          ("cat /proc/" pid "/cwd")|getline cwd;  # get 'cwd' (**broken**)
           print cwd ": " threads[pid]       # display 'cwd' and num threads
     }'

You also don't need all those backslashes. Newlines inside a quoted string don't need to be escaped (and some of them weren't even before newlines, there were comments after them).

Upvotes: 2

Related Questions