Как использовать переменные оболочки в сценарии 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 

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

8 ответов


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


это лучший способ сделать это. Он использует : (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}'

здесь мы получаем переменную после 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,}' a="$var1" b="$var2" file


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

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

это то же, что:

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

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


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

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

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


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

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

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

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


вы могли бы пройти в -v в имя переменной (v) и значение (=) переменной среды ("${v}"):

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

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

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

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

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

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

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

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

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

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


Я только что изменил ответ @Jotne на "for loop".

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

for i in chr{1..22} chrX chrY
do
awk -v chr="$i" '==chr' ../snp150.hg19.txt >> $chr.vcf.bed
echo $i
done