it-roy-ru.com

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

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

Сначала я попробовал с помощью сценария Shell:

$ 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 

Я запутался в этом.

204
hqjma

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

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


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

Он использует параметр -v: (P.S. используйте пробел после -v или он будет менее переносимым. Например, awk -v var= не 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}'

Предупреждение. Как пишет Эд Мортон, escape-последовательности будут интерпретироваться так, что \t становится реальным tab, а не \t, если это то, что вы ищете. Можно решить с помощью ENVIRON[] или получить к нему доступ через ARGV[]


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

Здесь мы получаем переменную после кода 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 для передачи данных inn в awk.

v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data

Чтобы получить данные inn для самого кода, а не только НАЧАТЬ:

v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test

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

Вы можете использовать переменную в коде 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

Подробнее о AWK и переменных
Читать этот FAQ

362
Jotne

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

$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
23
TrueY

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

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 для деталей и других опций. Первый метод, описанный выше, почти всегда является вашим лучшим вариантом и имеет наиболее очевидную семантику.

8
Ed Morton

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

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

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

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

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

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

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

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
3
Steven Penny
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
Shicheng Guo

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

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

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

0
Sina

Я только что изменил ответ @ Jotne на «для цикла». 

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