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

bash shell awk


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

Сначала я попробовал со скриптом оболочки:

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

Потом попробовал неуклюже:

$ 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 

Я в замешательстве.





Answer 1 Jotne


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

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


Использование -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}'

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

PS Если вам нравятся три вертикальные полосы в качестве разделителя ||| , он не может быть экранирован, поэтому используйте -F"[|][|][|]"

Пример получения данных из программы / функции inn в awk (здесь используется дата)

awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'

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

Здесь мы получаем переменную после кода 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

  • Таким образом, мы также можем установить разные разделители поля FS для каждого файла.

awk 'some code' FS=',' file1.txt FS=';' file2.ext

  • Переменная после блока кода не будет работать для блока BEGIN :

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


Here-string

Переменная также может быть добавлена ​​в awk , используя строку из оболочек, которые их поддерживают (включая Bash):

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

Это то же самое:

printf '%s' "$variable" | awk '{print $0}'

P.S.при этом переменная рассматривается как входной файл.


ENVIRON вход

Как пишет TrueY, вы можете использовать ENVIRON для печати переменных среды . Задав переменную перед запуском AWK, вы можете распечатать ее следующим образом:

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

ARGV Вход ARGV

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

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

Вводить данные в сам код,а не только в BEGIN:

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"
Если нет,то несколько строк будут добавлены как длинная одиночная строка.

Example:

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 .




Answer 2 TrueY


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

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



Answer 3 Ed Morton


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




Answer 4 Johnsyweb


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

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

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

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



Answer 5 Steven Penny


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

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

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

awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"