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

xuo3flqw  于 2023-01-17  发布在  Shell
关注(0)|答案(7)|浏览(205)

我发现了一些将外部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

我对这个很困惑。

x0fgdtte

x0fgdtte1#

将shell变量导入awk有几种方法。有些方法比其他方法更好。这应该涵盖了大多数方法。如果你有意见,请在下面留言。 版本1.5

使用-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[]访问它来解决
    • PS**如果您有竖线或其他regexp元字符作为分隔符,如|?(等,它们必须进行双转义。示例3竖线|||变为-F'\\|\\|\\|'。您也可以使用-F"[|][|][|]"

从程序/函数inn获取数据到awk的示例(此处使用日期)

awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'

将shell变量的内容作为regexp进行测试的示例:

awk -v var="$variable" '$0 ~ var{print "found it"}'

代码块后的变量

这里我们得到了awk代码后面的变量,只要你不需要BEGIN代码块中的变量,这个方法就可以很好地工作:

variable="line one\nline two"
echo "input data" | awk '{print var}' var="${variable}"
or
awk '{print var}' var="${variable}" file
  • 添加多个变量:

x1米20英寸1x

  • 这样我们也可以为每个文件设置不同的字段分隔符FS

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

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

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

这里串

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

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

这与以下内容相同:

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

P.S.这将变量视为文件输入。

输入

正如TrueY所写的,可以使用ENVIRON来打印环境变量。在运行AWK之前设置一个变量,可以如下所示打印出来:

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

输入

正如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添加很多命令,甚至用无效的命令使它崩溃。
不过,这种方法的一个有效用法是,当你想把一个符号传递给awk,以便应用于某个输入时,比如一个简单的计算器:

$ calc() { awk -v x="$1" -v z="$3" 'BEGIN{ print x '"$2"' z }'; }

$ calc 2.7 '+' 3.4
6.1

$ calc 2.7 '*' 3.4
9.18

使用一个填充了shell变量值的awk变量是无法做到这一点的,您需要在awk解释shell变量之前将其扩展为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和变量的详细信息

阅读此常见问题。

wtlkbnrh

wtlkbnrh2#

似乎根本没有提到好的老的ENVIRONawk内置散列。

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

6ovsh4lw3#

您可以在命令行选项-v中传递变量名(v)和环境变量("${v}")的值(=):

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

或者说得更清楚一些(v要少得多):

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

hc8w905p4#

您可以使用ARGV:

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

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

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

zqry0prt5#

我只是将@Jotne的答案改为“for循环”。

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

jei2mxaa6#

我不得不在日志文件的行首插入日期,它是这样做的:

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

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

5m1hhzi4

5m1hhzi47#

Pro头端

创建一个函数来处理这个问题会很方便,这样你就不必每次都输入所有的内容。使用所选的解决方案,我们得到...

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

相关问题