定义一个变量来与 bash 中的 awk 模式匹配

定义一个变量来与 bash 中的 awk 模式匹配

我试图抓取文本“time: X”后面的 100 行,其中 X 在 {0,40,80,...,200} 中。这是我到目前为止所拥有的:

#!/bin/bash
start=1
end=5
for i in $(seq $start $end);do 
  j=$(($i*40))
  awk '/time: $j/{for(i=1;i<=100;i++}{getline;print}}' file > fileX-$j.txt
done 

然而这似乎不起作用。我的问题具体是关于变量 $j 以及我需要如何在 '/time: ...' 之后定义它

例如,我有一个名为“file”的文件:

time: 1
1 2 3 
1 33 1 
2 31 4
time: 40
2 1 3 
9 8 77
1 3 4

在这种情况下我想制作两个单独的文件;第一个包含

1 2 3 
1 33 1 
2 31 4

第二个是:

1 2 3 
1 33 1 
2 31 4

我尝试将 $j 作为变量传递,如 mazs 提到的,但仍然给我空文件。这是我的做法:

awk -v jj=$j '/time: jj/{for(i=1;i<3;i++){getline;print}}' file > fileX-$j.txt

答案1

有两个问题。第一个是 shell 不会$j在单引号内展开:'$j'告诉 shell 您需要字符串$j,而不是变量的值j

在这种情况下,由于该值仅包含数字,因此您可以将其放在单引号之外:

awk '/time: '"$j"'/{for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

j请注意,如果包含正则表达式特殊字符(.、等)的值,*那么这些字符将被解释为这样。例如

j='2*3'
awk '/foo '"$j"' bar/'

该脚本将打印包含诸如foo 3 barfoo 23 barfoo 223 bar等内容而不是 的行foo 2*3 bar。如果值中有 a,/那么 awk 将看到正则表达式匹配结构的结尾;例如

j='2/3'
awk '/foo '"$j"' bar/'

会导致 awk 抱怨标记序列/foo 2/, 3, bar,/在语法上不正确。

您可以使用命令行选项为 awk 定义变量-v

j='a\tb'
awk -v j="$j" '{print j}'

请注意,这对 的值执行反斜杠扩展j。例如,上面的代码片段将每一行替换为a↦b制表符。

但这并不直接适用于您的情况,因为 awk 不会扩展内部变量/…//foo/匹配字符串foo,而不是变量的值foo。要在正则表达式匹配中使用变量,您需要使用以下match函数:

awk -v j="$j" 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

这适用于j不包含反斜杠的值;斜杠就可以了。例如,如果j设置为a/b*c,这将匹配诸如 、 等之类的行time: a/ctime: a/bc如果j设置为\t,这将匹配包含time:后跟空格和制表符的行。

要将 shell 变量的值传递给 awk,无论该值是什么,都要通过环境传递它。

export j
awk 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

或者,为了避免j在脚本的其余部分停留在环境中:

j="$j" awk 'match($0, "time: "+j) {for(i=1;i<=100;i++}{getline;print}}' file > fileX-"$j".txt

如果您想搜索文字字符串而不是正则表达式,则可以使用该index函数而不是match.例如

j='a*b'
awk 'index($0, "time: "+j)'

打印包含time: a*b.

答案2

您必须将 $j shell 变量传递给 awk:

awk -v jj="$j" '...'

请注意,这假设变量的值不包含反斜杠,因为参数 toawk -v经历了反斜杠扩展。

相关内容