GAWK 使用括号作为 FS

GAWK 使用括号作为 FS

当将 FS 的正则表达式设置为 space-open_parenthersis 或 opening_parenthesis-coma-space 时,我一直在努力解决 gawk 的工作问题,我尝试了多种方法,但没有一个达到预期的行为。FS="( ()|(), )" 第二。FS="[( ()(), )]"第 3 位(通过 ASCII OCT 代码)FS="[(\040\050)(\051\054\040)]"第 4 位FS="((\040\050)|(\051\054\040))"

我的输入文件是这样的https://phpaste.sourceforge.io/demo/paste.php?id=144这是一个只有一条记录(行)的文件,其中记录了我在 Debian 中的 apt-get 日志,列出了一些软件包。

我的 gawk 程序是这样的

#! /usr/bin/gawk -f
BEGIN {FS = "[(\040\050)(\051\054\040]"}
{
for(i=1;i<=NF;i=i+2) #I increased i by 2 because i want to print the odd numbered fields(only the names of the packages:architecture)  
    print $i
}`

我将在 bash 中执行它myawk.awk input.txt > output.txt


我很乐意在这里加上一个大词FXXX!!!!因为我刚刚解决了。我想这是对继续努力的奖励。我使用了FS = "(\\s\\\050)|(\\\051,\\s)"这个方法,尽管我不太明白为什么\\\在 ASCII 八进制代码之前有三个反斜杠。

有人会对此提供一些解释吗?比如为什么??我读过 AWK 读取正则表达式两次,这将需要,\\但我需要\\\(三次!!!)。

任何替代或不同的方法也将不胜感激!

提前致谢!

这是我想要的结果,谢天谢地,我从上次跑步中得到了它https://phpaste.sourceforge.io/demo/paste.php?id=145(包含其架构的软件包列表)

答案1

这件事你可能想多了。一点。我让它可以工作FS=" \\(|\\), ",甚至设法将其缩短为FS=" \\(|), ".

  • 你似乎相信你需要做 ,但其实你需要做的只是 。"(regex1)|(regex2)""regex1|regex2"
  • 您似乎相信,通过将括号括在分组括号中,内部括号将成为字面的文本括号。事实并非如此。正则表达式分组可以嵌套;要将括号视为字面的文本括号,您需要转义它们。
  • )仅在组内的正则表达式中是特殊的。如果(已转义,则)无需转义。

这就是棘手的地方。天真的,从上面来看,FS=" \(|), "应该足够好了。但是 GAWK 在字符串常量中的正则表达式方面存在问题;它在中讨论过GNU Awk 用户指南,第 9.1.3.1 节。它专注于在、或调用&的替换文本中获取文字,但它似乎也适用于:sub()gsub()gensub()FS

……有几个级别转义处理正在进行中。

首先,有词汇水平,即awk读取您的程序并构建其内部副本以执行的时间。然后是运行时级别,即awk实际扫描[程序并确定如何执行它]的时间。

在这两个级别上, awk查找可以出现在反斜杠之后的定义的字符集。在词汇级别,它查找列出的转义序列转义序列。  因此,对于awk在运行时级别处理的每个“\”,您必须在词法级别键入两个反斜杠。  ……

添加了强调(最后一句)。这似乎是说,如果我们想要设置为FS" \(|), " 转义左括号,将括号视为文字、文本括号),您需要分配 FS=" \\(|), "或指定-F' \\(|), ' (转义反斜杠)。您可以通过一个简单的测试来验证这一点:运行awk -F' \\(|), ',然后FS从程序中打印。它将显示为⁠ \(|), ⁠


一般来说,如果您想将特殊字符转换为非特殊字符(或者偶尔反之亦然),常见的传统方法是使用\(反斜杠)对其进行转义。但还有另一种特定于正则表达式的机制:使用表达式[…][…]表达式中唯一特殊的字符是^-](这取决于位置)。

  • [pq]表示一个p或一个q
  • [()]表示一个(或一个)
  • [(p]表示一个(或一个p
  • [(]  表示 a(或 ... 好吧,因为没有任何其他字符,所以它仅表示文字(

因此,如果您对反斜杠过敏,您可以设置FS=" [(]|), ".

答案2

这是我想出的另一种方法。它与您的输出完全匹配。由于split()每个项目都有额外的操作,它的效率可能较低,但更容易阅读和理解。

#!/usr/bin/awk -f

BEGIN { 
    FS="), "
}
{
    sub(/^Install:/, "") 
    for (i=1; i<=NF; i++) { 
        split($i, a, " ")
        print a[1]
    }
}

答案3

有一种更简单的方法可以在不使用 awk 的情况下完成相同的任务。您可以将 Perl 正则表达式与主要 Linux 发行版中提供的许多 grep 版本一起使用。使用我的 grep 版本(GNU grep 版本 2.27),以下提供与 awk 解决方案相同的输出。

grep -oP '(?<=\),).*?(?=\()' input.txt > output.txt

相关内容