将 shell 变量作为 /pattern/ 传递给 awk

将 shell 变量作为 /pattern/ 传递给 awk

我的 shell 函数之一具有以下内容:

function _process () {
  awk -v l="$line" '
  BEGIN {p=0}
  /'"$1"'/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '
}

,因此当调用 as 时_process $arg$arg会被传递为$1,并用作搜索模式。它是这样工作的,因为 shell 扩展$1代替了 awk 模式!也l可以在 awk 程序内部使用,用-v l="$line".一切都很好。

是否可以以同样的方式给出模式作为变量进行搜索?

以下将不起作用,

awk -v l="$line" -v search="$pattern" '
  BEGIN {p=0}
  /search/ {p=1}
  END{ if(p) print l >> "outfile.txt" }
  '

,因为 awk 不会解释/search/为变量,而是字面意思。

答案1

使用 awk 的~运算符,您不需要在右侧提供文字正则表达式:

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1; exit} 
        END {if(p) print l >> "outfile.txt"}
    '  
}

这里调用exit第一场比赛,因为我们不需要阅读其余的内容。您甚至不需要awk,就足够了并且可能更有效,并且避免了's进行反斜杠处理grep的问题:awk-v var='value'

function _process () {
    grep -qe "$1" && printf '%s\n' "$line"
}

根据图案,您可能需要grep -Eqe "$1"

答案2

awk  -v pattern="$1" '$0 ~ pattern'

存在一个问题awk,即\n在.因此,如果包含正则表达式中常见的反斜杠字符(使用 GNU 4.2 或更高版本,\f\\$1$1awk以 , 开头@/和结尾的值/也是一个问题)。另一种不受该问题困扰的方法是编写它:

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'

情况有多糟糕将取决于awk实施情况。

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ busybox awk -v 'a=\.' 'BEGIN {print a}'
.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo

不过,对于有效的转义序列,所有awks 的工作方式都是相同的:

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -vtx1 -tc
0000000  5c  5c  2d  5c  62  0a
          \   \   -   \   b  \n
0000006

$a(按原样通过的内容)

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -vtx1 -tc
0000000  5c  2d  08  0a
          \   -  \b  \n
0000004

\\更改为\\b更改为退格字符)。

答案3

尝试类似的方法:

awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'

答案4

您可以使用 eval 函数,该函数在运行 awk 之前解析此示例中的 nets 变量。

nets="searchtext"
eval "awk '/"${nets}"/'" file.txt

相关内容