如何在awk脚本中使用shell变量?

时间:2013-09-29 07:45:03

标签: bash shell awk

我找到了一些方法将外部shell变量传递给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 

我对此很困惑。

9 个答案:

答案 0 :(得分:396)

将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}'

警告即可。正如Ed Morton所写,转义序列将被解释为\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}"

这里串

还可以使用支持它们的shell(包括Bash)中的here-string将变量添加到awk

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输入

正如Steven Penny所写,您可以使用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"总是好的 如果没有,将添加多行作为长单行。

示例:

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和变量的更多信息

Read this faq

答案 1 :(得分:24)

似乎根本没有提到好的ENVIRON 内置哈希。其用法示例:

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

答案 2 :(得分:8)

根据处理的shell变量中的反斜杠的使用方式使用其中任何一个(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。上面的第一种方法几乎总是你最好的选择,并且具有最明显的语义。

答案 3 :(得分:5)

您可以使用变量名称(-v)和环境变量值v)传递command-line option ="${v}") :

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

或者使其更清晰(v s更少):

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

答案 4 :(得分:3)

您可以使用ARGV:

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

请注意,如果您要继续进入身体,则需要进行调整 ARGC:

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

答案 5 :(得分:1)

我必须在日志文件的行的开头插入日期,并且如下所示:

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

可以重定向到另一个文件进行保存

答案 6 :(得分:0)

我刚刚改变了@ Jotne的回答#34; for循环&#34;。

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

答案 7 :(得分: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

答案 8 :(得分:0)

专业提示

创建一个处理此问题的函数可能会派上用场,这样您就不必每次都键入所有内容。使用我们选择的解决方案...

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