链 awk 正则表达式匹配像 grep

Chain awk regex matches like grep

我正在尝试使用 awk select/remove 基于 CSV 文件中的单元格条目的数据。

如何链接 Awk 命令来构建复杂的搜索,就像我在 grep 中所做的那样?我计划根据多列单元格中的匹配条件使用 Awk select 行,而不仅仅是本例中的第一列。

测试数据

123,line1
123a,line2
abc,line3
G-123,line4
G-123a,line5

将 Awk 语句与中间文件分开

awk ' !~ /^[[:digit:]]/ {print [=11=]}' file.txt > output1.txt
awk ' !~ /^G-[[:digit:]]/ {print [=11=]}'  output1.txt > output2.txt
mv output2.txt output.txt
cat output.txt

链接或多行 grep 版本(我认为仅限于第一列)

grep -v \
     -e "^[[:digit:]]" \
     -e "^G-[[:digit:]]" \
     file.txt > output.txt
cat output.txt

如何重写 Awk 命令以避免中间文件?

您可以使用

awk ' !~ /^(G-)?[[:digit:]]/' file.txt > output.txt

awk 尝试在字段 1 中查找:

  • ^ - 字符串开头
  • (G-)? - 一个可选的 G- 字符序列(注意 awk 中的正则表达式风格是 POSIX ERE,因此 (...) 表示捕获组并且? 表示 一次或零次 量词)
  • [[:digit:]] - 一个数字。

如果找到匹配项,则不打印记录(=行)。否则,打印该行。

在您的 awk 命令和示例中,awk 认为 file.txt 只有一个字段,因为您没有定义 FS,因此使用默认的空白字段分隔符。

话虽如此,您可以像这样轻松地将两个模式匹配在一起:

awk '( !~ /^[[:digit:]]/) && ( !~ /^G-[[:digit:]]/) {print [=10=]}' file.txt

要使awk 使用逗号作为字段分隔符,您可以在BEGIN 块中定义它。在这个例子中,输出应该只是 line3

awk 'BEGIN {FS=","} ( !~ /^[[:digit:]]/) && ( !~ /^G-[[:digit:]]/) {print }' file.txt

通常,在 awk 中有可用的布尔运算符(它比 grep 更好!:))

awk '/match1/ || /match2/' file
awk '(/match1/ || /match2/ ) && /match3/' file

等等...


在您的示例中,您可以使用类似的东西:

awk -F, ' ~ /^[[:digit:]]/ ||  ~ /G-[[:digit:]]/' input >> output

注意:这只是一个如何使用布尔运算符的示例。也可以在这里使用正则表达式本身来表达替代匹配:

awk -F, ' ~ /^(G-)?[[:digit:]]/' input >> ouput

为了坚持你的问题,我会使用:

awk ' !~ /^[[:digit:]]/ &&  !~ /G-[[:digit:]]/' file.txt > output.txt

但我喜欢@Wiktor Stribiżew REGEX 方法!

我建议 awk 中那个 grep 命令的字面翻译是

awk '
  /^[[:digit:]]/ {next}
  /^G-[[:digit:]]/ {next}
  {print}
' file.txt

但是你有几个例子可以说明如何写得更简洁。

使用您展示的示例,这也可以在 grep 中在单个正则表达式中完成,我们不需要链接不同的正则表达式,添加此解决方案以防 you/anyone 需要它;可能会有帮助。

grep -v -E '^(G-)?[[:digit:]]' Input_file

解释: 简单的解释是,使用 grep-v 选项来省略那些行匹配上述模式。然后使用它的 -E 选项启用 ERE(扩展正则表达式)。在主程序中使用正则表达式 ^(G-)?[[:digit:]] 匹配如果行从 G- OR 数字开始然后不打印该行。