Передать переменную оболочки как / pattern / в awk

59

Имея следующее в одной из моих функций оболочки:

function _process () {
  awk -v l="$line" '
  BEGIN {p=0}
  /'"$1"'/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '
}

, Так что, когда называется _process $arg, $argполучает прошло , как $1и используется в качестве шаблона поиска. Это работает так, потому что оболочка расширяется $1вместо шаблона awk! Также lможет использоваться внутри программы awk, будучи объявленным с помощью -v l="$line". Все хорошо.

Можно ли таким же образом задать шаблон для поиска в качестве переменной?

Следующее не сработает,

awk -v l="$line" -v search="$pattern" '
  BEGIN {p=0}
  /search/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '

, поскольку awk не будет интерпретироваться /search/как переменная, а будет буквально.

branquito
источник

Ответы:

46

Используйте ~оператор awk , и вам не нужно предоставлять буквальное регулярное выражение в правой части:

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1} 
        END {if(p) print l >> "outfile.txt"}
    '  
}

Хотя это было бы более эффективно (не нужно читать весь файл)

function _process () {
    grep -q "$1" && echo "$line"
}

В зависимости от шаблона, может потребоваться grep -Eq "$1"

Гленн Джекман
источник
Это именно то, что решает это так, как я хотел (1-й пример), потому что он сохраняет семантику, которая была моей целью. Благодарю.
Бранкито
1
Я не заметил удаления блока BEGIN: неназначенная переменная обрабатывается как 0 в числовом контексте или как пустая строка в противном случае. Таким образом, неназначенная переменная будет ложной вif (p) ...
Гленн Джекман
да, я заметил, что для блока BEGIN необходимо каждый раз устанавливать его в ноль, поскольку он служит переключателем. Но интересно, что я попробовал сейчас использовать скрипт $0 ~ pattern, и он не работает, однако с /'"$1"'/ним работает !? : O
Бранкито
может быть , это что - то делать с тем , как $lineизвлекается, шаблон поиска делается на выходе whois $line, $lineисходя из файла в DO WHILE блока.
Бранкито
Пожалуйста, покажите содержимое $line- сделайте это в своем вопросе для правильного форматирования.
Гленн Джекман
17
awk  -v pattern="$1" '$0 ~ pattern'

Имеет проблему с awkрасширением escape-последовательностей ANSI C (например, \nдля новой строки, \fдля подачи формы, \\для обратной косой черты и т. Д.) $1. Таким образом, это становится проблемой, если $1содержит символы обратной косой черты, которые являются общими в регулярных выражениях (в GNU awk4.2 или выше значения, начинающиеся с @/и заканчивающиеся /, также являются проблемой ). Другой подход, который не страдает от этой проблемы, это написать:

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'

Насколько плохо это будет, будет зависеть от awkреализации.

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo

Все они awkработают одинаково для корректных escape-последовательностей:

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000   \   \   -   \   b  \n
0000006

(содержание $aпередано как есть)

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000   \   -  \b  \n
0000004

( \\изменено \и \bизменено на символ возврата).

Стефан Шазелас
источник
Итак, вы говорите, что если бы шаблон был, например, \d{3}для поиска трех цифр, это не сработало бы, как ожидалось, если бы я вас хорошо понял?
Бранкито
2
для \dкоторого недопустимая escape-последовательность C, это зависит от вашей awkреализации (запустить awk -v 'a=\d{3}' 'BEGIN{print a}'для проверки). Но для \` or \ b , yes definitely. (BTW, I don't know of any awk implementations that understands \ d` это означает цифру).
Стефан Шазелас
там написано: предупреждение awk - escape-последовательность \d' treated as plain d 'd {3}, так что, думаю, у меня возникнет проблема в этом случае?
Бранкито
1
Извините, мой плохой, в моем ответе была опечатка. Название затем переменной среды должно совпадать ENVIRON["PATTERN"]для PATTERNпеременной среды. Если вы хотите использовать переменную оболочки, вам нужно сначала экспортировать ее ( export variable) или использовать ENV=VALUE awk '...ENVIRON["ENV"]'синтаксис передачи env-var, как в моем ответе.
Стефан Шазелас
1
Потому что вам нужно экспортировать переменную оболочки, чтобы она передавалась в среде команде.
Стефан Шазелас
5

Попробуйте что-то вроде:

awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'
Охотник Эйдсон
источник
Если это ведет себя так же, как /regex/с точки зрения поиска шаблона, это может быть хорошим решением. Я попытаюсь.
Бранкито
1
Быстрые тесты, которые я проводил, работали одинаково, но я даже не стану это гарантировать ... :)
Хантер Эйдсон
0

Нет, но вы можете просто вставить шаблон в строку в двойных кавычках, которую передаете в awk:

awk -v l="$line" "BEGIN {p=0}; /$pattern/ {p=1}; END{ if(p) print l >> \"outfile.txt\" }"

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

Килиан Фот
источник
Безопасен ли этот способ, если он $patternсодержит пробелы, мой приведенный выше пример будет работать, так как $ 1 защищен двойными кавычками "$ 1", однако не уверен, что произойдет в вашем случае.
Бранкито
2
Ваш оригинальный пример заканчивает строку одинарными кавычками на втором ', затем защищает $1сквозные двойные кавычки, а затем добавляет еще одну строку в одинарных кавычках для второй половины программы awk. Если я правильно понимаю, это должно иметь тот же эффект, что и защита с $1помощью внешних одинарных кавычек - awk никогда не увидит двойные кавычки, которые вы помещаете вокруг него.
Килиан Фот
4
Но если $patternсодержит ^/ {system("rm -rf /")};, то у вас большие проблемы.
Стефан Шазелас
это только недостаток этого подхода, когда все заключено в ""?
Бранкито
-3

Вы можете использовать функцию eval, которая разрешает в этом примере переменную nets перед запуском awk.

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt
Noxy
источник