Используйте переменную оболочки в awk

8

Вот мой скрипт (чтобы найти файлы, которые содержат указанный шаблон):

find . -type f \
    -exec awk -v vawk="$1" '/'"$vawk"'/ {c++} c>0 { print ARGV[1]; exit 0 } END { if (! c) {exit 1}}' \{\} \;

Я хотел бы использовать мой сценарий с аргументом §:

MyScript.sh pattern

Моя проблема в том, что мне не удается поместить $1переменную в awk.

Когда я пытаюсь отладить свой скрипт

bash -x MyScript.sh pattern

Вот вывод:

+ find . -type f -exec awk -v vawk=pattern '// {c++} c>0 {print ARGV[1] ; exit 0 } END { if (! c) {exit 1}}' '{}' ';'

$vawkПеременная кажется пустым.

Есть идеи?

никола
источник

Ответы:

7

Вы, кажется, путаете переменные awk и переменные оболочки. awk -v vawk="$1"создает переменную awk с именем vawk, но вы пытаетесь использовать синтаксис оболочки ( $vawk). Это не работает, потому что в оболочке нет переменной с именем vawk. Я думаю, что вы хотите

awk -v vawk="$1" '$0 ~ vawk { c++ } # ...'
#                      ^ awk variable syntax
jw013
источник
1
Обратите внимание, что awkрасширяются C-подобные escape-последовательности $1, поэтому этот подход не работает, если он $1может содержать символы обратной косой черты (общие для регулярных выражений). ENVIRONВместо этого вы можете использовать специальный массив awk.
Стефан
6

Воспроизведенный из этого теперь закрытого как повторяющегося вопроса, поскольку он содержит предупреждения об ограничениях передачи переменных awk, которые могут оказаться полезными.

Переменная оболочки - это всего лишь переменная оболочки . Если вы хотите превратить его в переменную awk , вам нужен такой синтаксис:

awk -v x="$x" '$2 == x {print $1}' infile

или

awk '$2 == x {print $1}' x="$x" infile

Однако они страдают от проблемы: в них расширяются escape-последовательности (и в GNU awk4.2 или выше, если $xначинается с @/и заканчивается /, это рассматривается как переменная типа regexp ).

Так, например, если переменная оболочки содержит два символа обратной косой черты и n , переменная awk в конечном итоге будет содержать символ новой строки (и с gawk 4.2+, если она содержит @/foo/, переменная awk будет содержать fooи иметь тип regexp).

Другой подход (но для которого -vтребуется awk или nawk POSIX (в отличие от awk 1970-х годов, все еще найденного как /bin/awkв Solaris)) - это использование переменных среды:

x="$x" awk '$2 == ENVIRON["x"] {print $1}' infile

Другой подход (все еще с более новыми awk) заключается в использовании массива ARGV в awk:

awk 'BEGIN {x = ARGV[1]; delete ARGV[1]}
  $2 == x {print $1}' "$x" infile
Стефан Шазелас
источник