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

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

Сначала я попытался с помощью сценария оболочки:

$ 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 

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

10 ответов

Решение

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


Это лучший способ сделать это. Он использует -v опция: (PS используйте пробел после -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,$0}' a="$var1" b="$var2" file


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

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

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

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

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


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

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

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


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

Вы можете передать в опции командной строки -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], $0}' file "$v"

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

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

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

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

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

пример:

in.txt:


Переменная:

      var=$(awk '{print $1}' in.txt) 

команда:

      echo -e "$var" > out.txt

out.txt


Другая:

in.txt

      foo,aaa
bar,bbb

Переменная:

      var=$(awk -F "," '{print $1}' in.txt) 

out.txt

      foo
bar

или:

      var=$(awk -F "," '{print $2}' in.txt) 

out.txt

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

Совет профессионала

Было бы удобно создать функцию, которая обрабатывает это, чтобы вам не приходилось каждый раз вводить все подряд. Используя выбранное решение, получаем ...

      awk_switch_columns() {
     cat < /dev/stdin | awk -v a="$1" -v b="$2" " { t = \$a; \$a = \$b; \$b = t; print; } "
}

И использовать его как ...

      echo 'a b c d' | awk_switch_columns 2 4

Output:
a d c b
Другие вопросы по тегам