破译这个 AWK 脚本

破译这个 AWK 脚本
xev | awk -F'[ )]+' '/^KeyPress/ { a[NR+2] } NR in a { printf "%-3s %s\n", %5, %8}

当我使用 xev 时,我只需要某些信息。使用 xev 获取密钥代码信息的自然响应如下所示......

KeyPress event, serial 48, synthetic NO, window 0x1600001,
    root 0xf6, subw 0x0, time 754405, (348,566), root:(349,620),
    state 0x0, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (64) "d"
    XmbLookupString gives 1 bytes: (64) "d"
    XFilterEvent returns: False

KeyRelease event, serial 48, synthetic NO, window 0x1600001,
    root 0xf6, subw 0x0, time 754488, (348,566), root:(349,620),
    state 0x0, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (64) "d"
    XFilterEvent returns: False

AWK 脚本的结果只会返回:

40 d

这让我想学习 AWK :)

因此,在学习了 NR 并做了一些教程之后,我现在正在尝试解决这个问题。首先 -F 只是除以本例中的字段 '[ )]+' 我认为这是 1 个或多个空格或右括号的正则表达式。我不明白。我在前置词之前没有看到任何空格。另外,我不知道正则表达式框中的空格在这里有什么作用,因为我只了解了诸如 \s 之类的空白工具。所以我想看看哪些字段显示 $5 和 %8,因为它在我的分析中看起来不正确,我很困惑!

echo "state 0x0, keycode 12 (keysym 0x33, 3), same_screen YES," | awk '{print $8}'
same_screen
echo "state 0x0, keycode 12 (keysym 0x33, 3), same_screen YES," | awk '{print $5}'
(keysym

编辑:所以这是什么 printf "%-3s %s\n", $5, $8}?为什么输出与上面的 echo 示例如此不同?

显然,这是来自于魔法{a[NR+2] NR in a}。某种数组和 for 循环。

我看着 NR+2,它让我想到:因为当 AWK 启动时,NR 从 1 开始,加上 2 就会使其成为第三行。这看起来是正确的,因为我想要的所有信息都在第三行。

a[NR+2] 是怎么回事?对于 printf 中的 NR...?我了解 printf 我了解 for 循环。这里使用 NR 的方式让我感到困惑。

我想真正的问题是“a”发生了什么?这是我不知道的预定义的事情吗?

答案1

你似乎已经正确地推断{a[NR+2]} NR in a { ... }}出了什么;

  • /^KeyPress/ {a[NR+2]}当行的开头与字符串匹配时,在a带有索引的数组中创建一个(空值)元素NR+2NRKeyPress
  • NR in a/^KeyPress/因此对于下面两行匹配的行来说是正确的

在这方面,也许可以更透明地写为

awk -F'[ )]+' '/^KeyPress/ {n=NR+2} NR==n { printf "%-3s %s\n", $5, $8}'

一个可能更棘手的问题是为什么要打印的字段是$5and$8而不是$4and $7;这是因为使用非默认字段分隔符时,初始空格的处理方式有所不同:默认字段分割GNUawk手册的部分:

字段通常由空白序列(空格、制表符和换行符)分隔,而不是由单个空格分隔。一行中的两个空格不会界定空字段。字段分隔符 FS 的默认值是包含单个空格“”的字符串。如果 awk 以通常的方式解释该值,则每个空格字符将分隔字段,因此一行中的两个空格将在它们之间形成一个空字段。之所以不会发生这种情况,是因为单个空格作为 FS 的值是一种特殊情况——它用于指定分隔字段的默认方式。

如果 FS 是任何其他单个字符,例如“,”,则该字符的每次出现都会分隔两个字段。连续两次出现界定一个空字段。如果该字符出现在行的开头或结尾,那么也会界定一个空字段。空格字符是唯一不遵循这些规则的单个字符。

答案2

%-3s表示在 3 个字符宽的字段中打印字符串,并在右侧而不是左侧填充空格。所以它会打印

40  d

而不是

 40 d

答案3

我可以提供一些帮助,但这里的某人应该能够提供更深入的答案。但是,让我们分解一下。

首先,您使用 | 将 xev 的输出通过管道传输到 awk 中。

您是正确的,-F 正在定义 Awk 的列分隔符,并且匹配该字符的正则表达式是 [ )]+

它只会在您提供的示例输出中匹配一次。之后的一切都是 awk 脚本。

/^KeyPress/ 是另一个正则表达式,寻找以“KeyPress”开头的换行符...这似乎多余。

printf 的参数以逗号分隔,第一个参数是格式,因此:“%-3s %s\n”是格式。参见和这里

{printf "%-3s %s\n", %5, %8} 是否有可能是 { printf "%-3s %s\n", $5, $8} ?

我不太明白这一点。希望其他人可以解码它!顺便说一句-你可以使用帮助测试正则表达式。

相关内容