Как использовать переменные оболочки в скрипте awk?

202

Я нашел несколько способов передать внешние переменные оболочки в awk script, но я запутался в ' и ".

Сначала я попробовал с оболочкой script:

$ v=123test
$ echo $v
123test
$ echo "$v"
123test

Затем попытался awk:

$ awk 'BEGIN{print "'$v'"}'
$ 123test
$ awk 'BEGIN{print '"$v"'}'
$ 123

Почему разница?

Наконец, я пробовал это:

$ awk 'BEGIN{print " '$v' "}'
$  123test
$ awk 'BEGIN{print ' "$v" '}'
awk: cmd. line:1: BEGIN{print
awk: cmd. line:1:             ^ unexpected newline or end of string 

Я смущен этим.

  • 1
    Мне нравится -v, как показано ниже, но это действительно отличное упражнение для размышления о том, как защитить вещи от оболочки. Работая с этим, я впервые использовал обратную косую черту на пробелах и знаках доллара. Излишне говорить, что приведенные здесь примеры стоили моего времени.
  • 0
    Связанный: Разница между одинарными и двойными кавычками в awk .
Теги:
awk

8 ответов

336
Лучший ответ

Получение переменных оболочки в awk

может быть сделано несколькими способами. Некоторые лучше, чем другие. Это должно охватывать большинство из них. Если у вас есть комментарий, пожалуйста, оставьте ниже.


- Использование -v (лучший способ, самый портативный)

Он использует -v: (PS используйте пробел после -v или он будет менее переносимым. Например, awk -v var= not awk -vvar=)

variable="line one\nline two"
awk -v var="${variable}" 'BEGIN {print var}'
line one
line two

Это должно быть совместимо с большинством awk и переменная также доступна в блоке BEGIN:

Если у вас есть несколько переменных:

awk -v a="${var1}" -v b="${var2}" 'BEGIN {print a,b}'

- Переменная после блока кода

Здесь мы получаем переменную после кода awk. Это будет работать нормально, если вам не нужна переменная в блоке BEGIN:

variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file

Это также работает с несколькими переменными awk '{print a,b,$0}' a="$var1" b="$var2" file

Использование переменной таким способом не работает в блоке BEGIN:

echo "input data" | awk 'BEGIN {print var}' var="${variable}"

- Здесь строка

Переменная также может быть добавлена в awk используя здесь строку

awk '{print $0}' <<< "$variable"
test

Это так же, как:

echo "$variable" | awk '{print $0}'

PS, это угрожает переменной как входной файл


- ENVIRON вход

Когда вы пишете TrueY, вы можете использовать ENVIRON для печати Environmental Variables Установка переменной перед запуском AWK, вы можете распечатать ее так:

X=MyVar awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash

Редактировать: Как пишет "тот другой парень", это не обрабатывает обратную косую черту. Не рекомендуется.


- вход ARGV

Как пишет Стивен Пенни, вы можете использовать ARGV для передачи данных в awk.

v = "мои данные" awk 'BEGIN {print ARGV 1 }' "$ v" мои данные

Чтобы получить данные для самого кода, а не только для блока BEGIN, вам нужно уменьшить счетчик ARGV с помощью ARGC--

v = "мои данные" эхо "тест" | awk 'BEGIN {ARGC--} {print ARGV 1, $ 0}' "$ v" мой тест данных


- Переменная в коде: использовать с осторожностью

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

Это работает путем извлечения переменной в коде, поэтому она становится ее частью.

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

variable="line one\nline two"
awk 'BEGIN {print "'"$variable"'"}'
line one
line two

Вот пример внедрения кода:

variable='line one\nline two" ; for (i=1;i<=1000;++i) print i"'
awk 'BEGIN {print "'"$variable"'"}'
line one
line two
1
2
3
.
.
1000

Вы можете добавить много команд в awk таким образом. Даже сбой с недействительными командами.


- Дополнительная информация:

Использование двойной кавычки
Всегда полезно заключить в кавычки переменную "$variable"
Если нет, несколько строк будут добавлены в виде одной длинной строки.

Пример:

var="Line one
This is line two"

echo $var
Line one This is line two

echo "$var"
Line one
This is line two

Другие ошибки, которые вы можете получить без двойной кавычки:

variable="line one\nline two"
awk -v var=$variable 'BEGIN {print var}'
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ backslash not last character on line
awk: cmd. line:1: one\nline
awk: cmd. line:1:    ^ syntax error

И с одинарной кавычкой, это не расширяет значение переменной:

awk -v var='$variable' 'BEGIN {print var}'
$variable


Фигурные скобки
Как пишет Johnsyweb, было бы неплохо использовать фигурную скобку для имени переменной, чтобы было понятно, как оно называется.

awk -v var='${variable}' 'BEGIN {print var}'

против

awk -v var='$variable' 'BEGIN {print var}'
  • 1
    «Грязный и трудный для чтения» игнорирует более важную проблему безопасности при внедрении кода при прямой подстановке строк в код awk.
  • 1
    @CharlesDuffy. Вы на 100% правы. Вычистили еще немного.
Показать ещё 2 комментария
23

Кажется, что старый добрый ENVIRON awk встроенный хэш не упоминается вообще. Пример его использования:

$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
  • 3
    Это хорошее предложение, потому что оно передает данные дословно. -v не работает, если значение содержит обратную косую черту.
  • 1
    @thatotherguy Я этого не знал! Я думал, что если я использую awk -vx='\c\d' ... тогда он будет использован правильно. Но когда печатается x awk удаляет знаменитое: awk: warning: escape sequence '\c' treated as plain 'c' сообщение об ошибке awk: warning: escape sequence '\c' treated as plain 'c' ... Спасибо!
8

Использовать любой из них в зависимости от того, как вы хотите обратную косую черту в обрабатываемых переменных оболочки (avar - это переменная awk, svar - это переменная оболочки):

awk -v avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file

Подробнее см. http://cfajohnson.com/shell/cus-faq-2.html#Q24. Первый метод, приведенный выше, почти всегда является вашим лучшим вариантом и имеет самую очевидную семантику.

5

Вы можете передать параметр командной строки -v с именем переменной (v) и значением (=) переменной окружения ("${v}"):

% awk -vv="${v}" 'BEGIN { print v }'
123test

Или сделать его более понятным (с гораздо меньшим количеством v):

% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test
3

Вы можете использовать ARGV:

v=123test
awk 'BEGIN {print ARGV[1]}' "$v"

Обратите внимание, что если вы собираетесь продолжать работать в теле, вам нужно будет настроить ARGC:

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
0
for i in chr{1..22} chrX chrY
do
awk -v chr="$i" '$1==chr' ../snp150.hg19.txt >> $chr.vcf.bed
echo $i
done
0

Я просто изменил @Jotne ответ для "for loop".

for i in 'seq 11 20'; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
0

Мне пришлось вставлять дату в начале строк файла журнала, и она выполнялась, как показано ниже:

DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log

Он может быть перенаправлен на другой файл для сохранения

  • 0
    Двойная кавычка - одинарная кавычка - двойная кавычка была именно то, что мне нужно, чтобы моя работа
  • 0
    Это уже упоминалось в принятом ответе как метод, который вы не должны использовать из-за уязвимостей внедрения кода. Таким образом, информация здесь избыточна (уже описана в принятом ответе) и неполна (не затрагивает проблемы с этим методом).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню