提问人:hqjma 提问时间:9/29/2013 最后编辑:codeforesterhqjma 更新时间:8/19/2023 访问量:671351
如何在 awk 脚本中使用 shell 变量?
How do I use shell variables in an awk script?
问:
我找到了一些将外部 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
我对此感到困惑。
答:
您可以使用环境变量 () 的变量名称 () 和值 () 传入命令行选项:-v
v
=
"${v}"
% awk -vv="${v}" 'BEGIN { print v }'
123test
或者说得更清楚(用更少的 s):v
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test
评论
-v
v=
可以通过多种方式 #Getting shell 变量。有些比其他的更好。这应该涵盖其中的大部分。如果您有任何意见,请在下面留下。1.5 版
awk
使用(最好的方式,最便携)-v
使用选项:(P.S. 在后面使用空格,否则它的便携性会降低。-v
-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[]
聚苯乙烯如果您有竖线或其他正则表达式元字符作为分隔符等,则必须对它们进行双重转义。示例 3 竖条变为 .您也可以使用 .|?(
|||
-F'\\|\\|\\|'
-F"[|][|][|]"
从程序/函数 inn 获取数据的示例(此处使用日期)
awk
awk -v time="$(date +"%F %H:%M" -d '-1 minute')" 'BEGIN {print time}'
将 shell 变量的内容作为正则表达式进行测试的示例:
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
- 添加多个变量:
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}"
这里字符串
变量也可以添加到使用支持它们的 shell(包括 Bash)的 here-string 中:awk
awk '{print $0}' <<< "$variable"
test
这与以下相同:
printf '%s' "$variable" | awk '{print $0}'
P.S. 这会将变量视为文件输入。
ENVIRON
输入
正如 TrueY 所写的那样,您可以使用 打印环境变量。
在运行 AWK 之前设置一个变量,您可以像这样打印出来:ENVIRON
export X=MyVar
awk 'BEGIN{print ENVIRON["X"],ENVIRON["SHELL"]}'
MyVar /bin/bash
或者对于未导出的变量:
x=MyVar
x="$x" awk 'BEGIN{print ENVIRON["x"],ENVIRON["SHELL"]}'
MyVar /bin/bash
ARGV
输入
正如 Steven Penny 所写,您可以使用以下方法将数据导入 awk:ARGV
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 脚本文本的一部分。(见下面 Ed M 的评论。
额外信息:
使用双引号
双引号变量
总是好的 如果没有,将添加多行作为长单行。"$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 和变量的详细信息
评论
-v
awk -v a=b cmds path1 path2
awk cmds a=b path1 path2
-v
awk cmds path1 a=b path2
BEGIN
ARGV[]
FILENAME
ARGV[]
FILENAME==ARGV[1]
NR==FNR
FS
-v
ENVIRON[]
there is no good way to use -v to emulate awk cmds path1 a=b path2
awk -v a=b cmds path1 path2
awk cmds path1 a=b path2
awk -v a=b cmds path1 path2
a
似乎根本没有提到旧的 awk 内置哈希。其用法示例:ENVIRON
$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
评论
-v
awk -v x='\c\d' ...
x
awk: warning: escape sequence '\c' treated as plain 'c'
-v
\t
-v
ARGV[]
ENVIRON[]
我不得不在日志文件的行的开头插入日期,如下所示:
DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log
它可以重定向到另一个文件进行保存
评论
您可以使用 ARGV:
v=123test
awk 'BEGIN {print ARGV[1]}' "$v"
请注意,如果您要继续进入身体,则需要进行调整 ARGC:
awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
评论
我只是将@Jotne的答案更改为“for 循环”。
for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
评论
-v
专业提示
创建一个处理此问题的函数可能会派上用场,这样您就不必每次都键入所有内容。使用选定的解决方案,我们得到...
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
评论
$
评论
/var/
awk -v var="$var" '$0 ~ var'
/.../
/.../
"..."