Как предварительно построить оператор awk для передачи в awk в командной строке? - PullRequest
3 голосов
/ 02 июля 2010

У меня есть сценарий оболочки, который создает awk-программу как строку, а затем передает эту строку в awk. Это потому, что я хочу использовать значения переменных оболочки в программе awk.

Мой код выглядит так:

awk_prog="'{if (\$4~/$shell_var/) print \$1,\$2}'"
echo $awk_prog
awk $awk_prog $FILENAME

Однако, когда я передаю строку в awk, я всегда получаю сообщение об ошибке:

'{if ($4~/regex/) print $1,$2}'
awk: '{if
awk: ^ invalid char ''' in expression

Что означает это сообщение об ошибке? Я пробовал переключатель -F: но это не помогает. Как я могу решить эту проблему?

Спасибо.

Ответы [ 3 ]

5 голосов
/ 02 июля 2010

Это вызвано цитированием оболочки. Будет работать следующее:

awk_prog="{ if (\$4 ~ /$shell_var/) print \$1, \$2 }"
echo "$awk_prog"
awk "$awk_prog" $FILENAME

Когда вы запускаете awk '{ print }' foo из командной строки, оболочка интерпретирует и удаляет кавычки вокруг программы, поэтому awk получает два аргумента - первый - текст программы, а второй - имя файла foo. Ваш пример отправлял awk текст программы '{if ...}', что является недопустимым синтаксисом для awk. Внешние кавычки не должны присутствовать.

В приведенном выше фрагменте кода оболочка использует кавычки в строке awk_prog=, чтобы сгруппировать содержимое строки в одно значение, а затем присвоить его переменной awk_prog. Когда он выполняет строку awk "$awk_prog"..., вы должны заключить в кавычки расширение $awk_prog, чтобы awk получил текст программы в виде одного аргумента.

4 голосов
/ 02 июля 2010

Есть еще один способ получить переменную оболочки в awk - используйте опцию awk -v:

awk -v pattern="$shell_var" '$4 ~ pattern {print $1, $2}' "$FILENAME"

Используйте -v несколько раз, если у вас есть несколько переменных для передачи в awk.

Если вы действительно хотите хранить вашу awk-программу в переменной оболочки, создайте ее, используя printf:

awk_script="$( printf '$4 ~ /%s/ {print $1, $2}' "$shell_var" )"
awk "$awk_script" "$FILENAME"

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

1 голос
/ 03 июля 2010

Другое (более простое IMO) решение, которое (я думаю) обращается к тому, что вы интуитивно пытаетесь сделать, - это просто использовать eval.Вы хотите, чтобы оболочка вела себя так, как если бы вы буквально набрали:

awk '{if ($4~/foo/) print $1,$2}' path

(где foo и path - это буквальное содержимое $ shell_var и $ FILENAME).Чтобы это произошло, просто шлепните eval в начале вашей последней строки (и, возможно, в кавычках для хорошей меры, но в этом случае они не нужны), чтобы ваша последняя строка была:

eval "awk $awk_prog $FILENAME"
...