如何使用 awk 检查线上的第一个模式?

How can to check for first pattern on the line with awk?

这里有一个令人困惑的(对我来说)的例子。这个 awk 表达式给出了期望的结果并打印:“match

$ echo -e "<?xml version="1.1" encoding="UTF-8" standalone="no"?>\n<databaseChangeLog" |
  awk  -e'/[[:space:]]*<?xml /{ print "match"; } { quit 0; }'
match
$ 

我们实际上希望任何匹配项都是行中的第一个模式。据我所知,这应该是string/line anchor,^的开头。然而添加 ^ 失败,如图所示:

$ echo -e "<?xml version="1.1" encoding="UTF-8" standalone="no"?>\n<databaseChangeLog" |
  awk  -e'/^[[:space:]]*<?xml /{ print "match"; } { quit 0; }'
$ 
$ # NO match

使用 gawk,版本:

$ awk --version
GNU Awk 5.0.1, API: 2.0 (GNU MPFR 4.0.2, GNU MP 6.2.0)
Copyright (C) 1989, 1991-2019 Free Software Foundation.
  ... 

缺少什么?

您将 ^ 添加到您的输入中,而不是将其添加到您的代码中应该与输入匹配的正则表达式中,即您做了:

$ echo '^foobar' | awk '/bar/'
^foobar

而不是:

$ echo 'foobar' | awk '/^bar/'
$

您也在使用 ? 正则表达式元字符,但想要文字 ? 而不是,而您正尝试使用不存在的关键字 quit,而我假设您的意思是exit (所以你的代码实际上做的是连接一个未定义的变量与数字 0 导致字符串 0 然后你只是丢弃)但你只退出 0这是默认的,所以这都是多余的。

我认为这可能是您想要做的:

awk '/^[[:space:]]*<\?xml /{ f=1; exit } END{ if (f) print "match"; exit !f }'

例如:

$ printf '%s\n' '<?xml version="1.1" encoding="UTF-8" standalone="no"?>' '<databaseChangeLog' |
    awk '/^[[:space:]]*<\?xml /{ f=1; exit } END{ if (f) print "match"; exit !f }'
match
$ echo $?
0

$ printf '%s\n' 'foo<?xml version="1.1" encoding="UTF-8" standalone="no"?>' '<databaseChangeLog' |
    awk '/^[[:space:]]*<\?xml /{ f=1; exit } END{ if (f) print "match"; exit !f }'
$ echo $?
1

以上内容适用于任何 POSIX awk。如果您有一个不支持 POSIX 字符 类 的非常旧的 awk,那么只需将 [[:space:]] 更改为 [ \t] 即可在任何 awk 中使用。

同时考虑将匹配或不匹配打印到 stderr:

$ printf '%s\n' '<?xml version="1.1" encoding="UTF-8" standalone="no"?>' '<databaseChangeLog' |
    awk '/^[[:space:]]*<\?xml /{ f=1; exit } END{ print (f ? "" : "no ") "match" | "cat>&2"; exit !f }'
match

$ printf '%s\n' 'foo<?xml version="1.1" encoding="UTF-8" standalone="no"?>' '<databaseChangeLog' |
    awk '/^[[:space:]]*<\?xml /{ f=1; exit } END{ print (f ? "" : "no ") "match" | "cat>&2"; exit !f }'
no match