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

Bash 如何在awk脚本中使用shell变量?,bash,shell,awk,Bash,Shell,Awk,我找到了一些将外部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 $ a

我找到了一些将外部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

或者更清楚地说(使用更少的
v
s):

#将shell变量放入
awk
可能有几种方法。有些方法比其他方法更好。这应该涵盖其中的大部分。如果您有意见,请在下面留下。v1.5


##使用
-v
(最好的方式,最便携) 使用
-v
选项:(请在
-v
之后使用空格,否则它的可移植性会降低。例如,
awk-v var=
而不是
awk-vvar=

这应该与大多数
awk
兼容,并且变量也可在
BEGIN
块中使用:

如果您有多个变量:

awk -v a="$var1" -v b="$var2" 'BEGIN {print a,b}'
警告。正如Ed Morton所写,转义序列将被解释为
\t
成为真正的
选项卡
,而不是
\t
,如果这是您搜索的内容。可以通过使用
环境[]
或通过
ARGV[]访问它来解决

PS如果您喜欢三个竖条作为分隔符
| | | |
,它不能被转义,所以请使用
-F“[|][|][|]

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

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


##代码块后的变量 这里我们得到
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”文件

  • 这样,我们还可以为每个文件设置不同的字段分隔符
    FS
awk'some code'FS=','file1.txt FS=';'file2.ext

  • 代码块后的变量对于
    BEGIN
    块不起作用:
echo“输入数据”| awk“开始{print var}”var=“${variable}”


##这里是字符串 还可以使用来自支持变量的shell(包括Bash)的命令将变量添加到
awk

另外,这将变量视为文件输入


##
环境
输入 正如TrueY所写,您可以使用
环境
打印环境变量。 在运行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
要将数据输入代码本身,而不仅仅是开始:

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
不使用双引号可以得到的其他错误:

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 avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
###有关AWK和变量的更多信息
.

根据您希望如何处理shell变量中的反斜杠,使用这两种方法之一(
avar
是awk变量,
svar
是shell变量):


有关详细信息和其他选项,请参阅。上面的第一种方法几乎总是您最好的选择,并且具有最明显的语义。

似乎根本没有提到好的旧
环境
内置哈希。其用法示例如下:

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

我必须在日志文件行的开头插入日期,操作如下:

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:


我刚刚改变了@Jotne对“for loop”的回答

专业提示 它可以方便地创建一个处理此问题的函数,这样您就不必每次都键入所有内容

awk_switch_columns() {
     cat < /dev/stdin | awk -v a="$1" -v b="$2" " { t = \$a; \$a = \$b; \$b = t; print; } "
}

“凌乱且难以阅读”在直接将字符串替换到awk代码中时忽略了代码注入的更重要的安全问题。阅读上面的答案,我可以运行我的脚本而不会出错,但它不能完成以下任务:awk-v repo=“$1”-v tag=“$2”{sub(/image:registryabx.azurecr.io\/{print repo}:([a-z0-9]+)$/,“image:registryabc.azurecr.io/{print repo}:{print tag}”);}1'/services/appscompose.yaml>>newcompose.yaml.是因为嵌套的括号{?@DarionBadlydone尝试这个
awk-v repo=“$1”-v tag=“$2”'开始{print”repo=“repo”,tag=“tag}“
。它将查看它是否打印变量。如果您无法理解,请发布自己的问题。@Jotne yes它打印值,因此我尝试了以下方法:awk-v repo=“$1”-v tag=“$2”{print”{sub(/image:registryabc.azurecr.io/“repo”):([a-z0-9]+)$/,\“image:registryabc.azurecr.io/“repo:”tag“\”;}1}'./services/appscompose.yaml>>newcompose.yaml,但它不作为aspected工作。它用打印的command@DarionBadlydonesed是一个比awk更糟糕的选择,因为它没有
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 avar="$svar" '... avar ...' file
awk 'BEGIN{avar=ARGV[1];ARGV[1]=""}... avar ...' "$svar" file
$ X=Solaris awk 'BEGIN{print ENVIRON["X"], ENVIRON["TERM"]}'
Solaris rxvt
DATE=$(date +"%Y-%m-%d")
awk '{ print "'"$DATE"'", $0; }' /path_to_log_file/log_file.log
v=123test
awk 'BEGIN {print ARGV[1]}' "$v"
awk 'BEGIN {ARGC--} {print ARGV[2], $0}' file "$v"
for i in `seq 11 20`; do host myserver-$i | awk -v i="$i" '{print "myserver-"i" " $4}'; done
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