Variável de ambiente não expandida dentro do argumento da linha de comando

Variável de ambiente não expandida dentro do argumento da linha de comando

Eu tenho um arquivo user-pid.out2que possui "usernumber" e "process id" como duas colunas. com base no número do usuário, quero encontrar o ID do processo correspondente. as duas primeiras linhas abaixo não mostram a saída correta, mas quando codifico o usuário como 62 nas linhas 3 e 4, ele mostra o ID do processo correspondente ao usuário 62. Alguém poderia ajudar, por favor.

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

Responder1

@artm mostrou uma técnica em que você coloca aspas duplas no script awk e escapa de vários caracteres. Aqui estão três outras técnicas

Saia das aspas simples para permitir que o shell expanda a variável

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

Passe a variável shell para uma variável awk

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

Se a variável for exportada, use o array ENVIRON do awk

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

Este último deve ser o preferido.

Na primeira abordagem, como na de @artm, o conteúdo da variável shell é incorporado dentro do awkcódigo, de modo que se torna umvulnerabilidade de injeção de comandose o conteúdo da variável não for rigidamente controlado (por exemplo, with USR='blah" || system("reboot") || "', isso chamaria reboot).

O segundo não introduz uma vulnerabilidade de injeção de comando, mas se $USRcontiver caracteres de barra invertida, a usr awkvariável não conterá a mesma coisa que a $USRvariável shell, pois awkexpande sequências de escape de barra invertida semelhantes a C.

Usar ENVIRONnão tem nenhum desses problemas.

Responder2

o "$USR"no primeiro exemplo não é expandido porque ocorre dentro da string entre aspas simples '$1 == "$USR" { print $2 }', então este código está procurando uma linha com a primeira coluna sendo "$USR", não 62.

O seguinte deve funcionar:

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

Mudanças:

  1. a linha de comando do awk usa aspas duplas, então $USR é expandido
  2. cifrões e caracteres de aspas dentro do programa awk são escapados
  3. $()é usado em vez de crases, entãoas barras invertidas são tratadas corretamente

Observe que, como o valor de USRé interpolado diretamente no script awk, ele só funciona se esse valor contiver apenas caracteres que o awk interpretará literalmente: se $USRcontém \ou ", o inferno vai explodir -  "seria o fim da string awk literal, e \citaria o próximo caractere.

informação relacionada