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

bash shell awk


我发现了一些将外部shell变量传递给 awk 脚本的方法,但是我对 '" 感到困惑。

首先,我用shell脚本试了一下。

$ 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


将shell变量放入 awk

可以通过几种方式完成。有些比其他更好。这应该涵盖其中的大多数。如果您有任何评论,请在下面离开。v1.5


使用 -v (最佳方法,最可移植)

使用 -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}'

警告。正如Ed Morton所写,转义序列将被解释,因此 \t 成为一个真正的 tab 而不是 \t 如果这是您要搜索的内容)。可以使用 ENVIRON[] 解决,也可以通过 ARGV[] 访问

PS如果您喜欢三个竖线作为分隔符 ||| ,无法将其转义,因此请使用 -F"[|][|][|]"

从程序/函数客栈获取数据到 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

  • 这样,我们还可以为每个文件设置不同的Field Separator FS

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

  • 代码块之后的变量不适用于 BEGIN 块:

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


Here-string

也可以使用支持字符串的shell(包括Bash)中的here-string将变量添加到 awk

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

这与。

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

P.S.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" 总是好的
如果不是,多行将作为一个长的单行添加。

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

阅读此常见问题解答




Answer 2 TrueY


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

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



Answer 3 Ed Morton


根据您希望在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。上面的第一种方法几乎总是您的最佳选择,并且具有最明显的语义。




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


你可以利用ARGV。

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

需要注意的是,如果你要继续进入正文,需要调整ARGC。

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