我找到了一些将外部 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
我对此感到困惑。
/var/
。相反,使用波浪号:awk -v var="$var" '$0 ~ var'
#Getting shell variables into 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"[|][|][|]"
从程序/函数 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
这样我们也可以为每个文件设置不同的Field Separator 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}'
PS这将变量视为文件输入。
环境输入
正如 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
添加大量命令。甚至使用无效命令使其崩溃。
但是,这种方法的一个有效用途是当您想将符号传递给 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 和变量的更多信息
似乎根本没有提到旧的 ENVIRON
awk 内置哈希。其用法示例:
$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
-v
不起作用。
awk -v x='\c\d' ...
那么它将被正确使用。但是当 x
打印时,awk 会丢弃著名的:awk: warning: escape sequence '\c' treated as plain 'c'
错误消息...谢谢!
-v
就是这样设计的,因此您可以在变量中使用 \t
并使其与数据中的文字标签匹配,例如。如果这不是您想要的行为,则不要使用 -v
,而是使用 ARGV[]
或 ENVIRON[]
。
根据您希望如何处理 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。上面的第一种方法几乎总是您的最佳选择,并且具有最明显的语义。
您可以使用变量名 (v
) 和环境变量 ("${v}"
) 的值 (=
) 传入 command-line option -v
:
% awk -vv="${v}" 'BEGIN { print v }'
123test
或者说得更清楚(v
少得多):
% environment_variable=123test
% awk -vawk_variable="${environment_variable}" 'BEGIN { print awk_variable }'
123test
您可以使用 ARGV:
v=123test
awk 'BEGIN {print ARGV[1]}' "$v"
请注意,如果您要继续进入身体,则需要调整 ARGC:
awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
我刚刚更改了@Jotne 对“for loop”的回答。
for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
-v
选项。如果你想展示如何在循环中运行 Awk,那真的是一个不同的问题。
我必须在日志文件行的开头插入日期,如下所示:
DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log
可以重定向到另一个文件保存
专家提示
创建一个处理此问题的函数可能会派上用场,这样您就不必每次都键入所有内容。使用我们得到的选定解决方案...
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
例子:
在.txt:
foo
bar
多变的:
var=$(awk '{print $1}' in.txt)
命令:
echo -e "$var" > out.txt
出.txt
foo
bar
其他:
在.txt
foo,aaa
bar,bbb
多变的:
var=$(awk -F "," '{print $1}' in.txt)
出.txt
foo
bar
或者:
var=$(awk -F "," '{print $2}' in.txt)
出.txt
aaa
bbb
awk -v repo="$1" -v tag="$2" 'BEGIN {print "repo="repo,"tag="tag}'
。它将查看是否打印变量。如果您无法弄清楚,请发布自己的问题。-v
是“最好、最便携的方式”。awk -v a=b cmds path1 path2
(几乎)等价于awk cmds a=b path1 path2
,但没有很好的方法可以使用-v
来模拟awk cmds path1 a=b path2
在参数中定义变量是一种非常有用的技术,它同样具有可移植性,我认为它是“更好的”。