本文翻译自StackOverflow提问—— “How do I use shell variables in an awk script?”,但更改了文章段落结构和部分表述。
方式1、使用 -v
选项(最好的方式,兼容性最佳)
使用-v
选项(P.S. 记得在选项和变量名之间加上空格)
variable="line one\nline two"
awk -v var="$variable" 'BEGIN {print var}'
line one
line two
该方式应该是兼容大多数版本的awk的,并且,变量也能在BEGIN
块中被访问。
如果你想向awk中传递多个变量:
awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
警告 : 带\
的字符序列会被转义,即\t
会变成真的tab
。所以如果你想在awk中对\t
进行保留,那么你可以用ENVIRON[]
或者ARGV[]
这两个环境变量来获取。
(P.S. 如果你喜欢使用三个竖条|||
来作为分隔符,那么它们不会被转义,可以用-F "[|][|][|]"
)
方式2、使用环境变量ENVIRON[]
在调用awk
之前,先设置好变量,然后在awk
中通过环境变量ENVIRON
来获取:
X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
方式3、使用ARGV
将目标变量作为awk命令的参数传入:
v="my data"
awk 'BEGIN {print ARGV[1]}' "$v"
my data
如果希望不仅仅局限在awk的BEGIN块中访问目标变量,可以这样:
v="my data"
echo "test" | awk 'BEGIN{var=ARGV[1];ARGV[1]=""} {print var, $0}' "$v"
my data test
方式4、awk代码块后部追加变量
将待传递变量追加到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}"
方式5、Here-string
目标变量也可以通过 here-string 的方式传给awk,前提是shell支持here-string(bash支持):
awk '{print $0}' <<< "$variable"
test
这和下边的写法是一致的:
printf '%s' "$variable" | awk '{print $0}'
即:here-string 被当作文件输入处理了
here-string 不支持在 BEGIN
代码块中使用!
方式6、!!慎用!! 直接在awk代码块中使用
目标变量也可以直接在awk代码中使用,但是这会有“代码注入”的风险。如果别有用心的人,在变量中加入一些可执行的“坏”东西,而被awk当作code的一部分给执行了,那就糟了:
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执行,甚至可以导致机器宕机。