当将 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