2

I have a file user-pid.out2 which has "usernumber" and "process id" as two columns. based on usernumber I want to find corresponding process id. the first two lines below does not show the output correct but when I hardcode the user as 62 in line 3 & 4 it shows the process id corresponding to user 62. Could someone help please.

USR=62
usrpid=`awk '$1 == "$USR" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo "first:" $USR $usrpid
# This shows 62 and blank for process id

usrpid=`awk '$1 == "62" {print $2}' /home/hu/batchhu/dbscripts_tst2/user-pid.out2`
echo  "second:" $USR $usrpid
# This shows 62 and process id corresponding to this user in the file user-pid.out2
Anil
  • 21

2 Answers2

9

@artm showed a technique where you double-quote the awk script and escape various characters. Here are 3 other techniques

Break out of the single quote to let the shell expand the variable

usrpid=$(awk '$1 == "'"$USR"'" {print $2}' file)

Pass the shell variable into an awk variable

usrpid=$(awk -v usr="$USR" '$1 == usr {print $2}' file)

If the variable is exported, use awk's ENVIRON array

usrpid=$(awk '$1 == ENVIRON["USR"] {print $2}' file)

That latter one should be the preferred one.

In the first approach like for @artm's one, the content of the shell variable is embedded inside the awk code, so that becomes a command injection vulnerability if the content of the variable is not tightly controlled (for instance, with USR='blah" || system("reboot") || "', that would call reboot).

The second one does not introduce a command injection vulnerability but if $USR contains backslash characters, the usr awk variable will not contain the same thing as the $USR shell variable as awk expands C-like backslash escape sequences in there.

Using ENVIRON has none of those issues.

glenn jackman
  • 85,964
3

the "$USR" in the first example isn't expanded because it occurs inside the single-quoted string '$1 == "$USR" { print $2 }', so this code is looking for a row with the first column being "$USR", not 62.

The following should work:

usrpid=$(awk "\$1 == \"$USR\" {print \$2}" /home/hu/batchhu/dbscripts_tst2/user-pid.out2)

Changes:

  1. the awk command line uses double quotes so $USR is expanded
  2. dollar signs and quote characters inside the awk program are escaped
  3. $() is used instead of backticks so the backslashes are handled correctly

Do note that since the value of USR is interpolated directly into the awk script, it only works if that value only contains characters that awk will interpret literally: if $USR contains \ or ", all hell will break loose — " would be the end of the awk string literal, and \ would quote the next character.

artm
  • 466