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

bra*_*ito 71 shell awk quoting variable

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

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

,所以当被称为 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" }
  '
Run Code Online (Sandbox Code Playgroud)

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

gle*_*man 53

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

function _process () {
    awk -v l="$line" -v pattern="$1" '
        $0 ~ pattern {p=1} 
        END {if(p) print l >> "outfile.txt"}
    '  
}
Run Code Online (Sandbox Code Playgroud)

虽然这会更有效率(不必阅读整个文件)

function _process () {
    grep -q "$1" && echo "$line"
}
Run Code Online (Sandbox Code Playgroud)

根据模式,可能需要 grep -Eq "$1"


Sté*_*las 21

awk  -v pattern="$1" '$0 ~ pattern'
Run Code Online (Sandbox Code Playgroud)

具有这样一个问题,awk扩展ANSI C转义序列(如\n为换行,\f为的形式进料,\\用于反斜杠等)中$1。因此,如果$1包含在正则表达式中常见的反斜杠字符就会成为一个问题(在 GNU awk4.2 或更高版本中,以 开头@/和结尾的值/也是一个问题)。另一种不受该问题影响的方法是编写它:

PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'
Run Code Online (Sandbox Code Playgroud)

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

$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -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
Run Code Online (Sandbox Code Playgroud)

awk尽管对于有效的转义序列,所有s 的工作方式相同:

$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000   \   \   -   \   b  \n
0000006
Run Code Online (Sandbox Code Playgroud)

$a按原样传递的内容)

$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000   \   -  \b  \n
0000004
Run Code Online (Sandbox Code Playgroud)

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

  • 对于不是有效的 C 转义序列的 `\d`,这取决于你的 `awk` 实现(运行 `awk -v 'a=\d{3}' 'BEGIN{print a}'` 来检查)。但是对于 `\\` 或 `\b`,肯定是的。(顺便说一句,我不知道任何将 `\d` 理解为数字的 awk 实现)。 (2认同)
  • 因为您需要导出 shell 变量才能将其传递到环境中的命令。 (2认同)

小智 5

尝试类似:

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