awk 中的 Slurp 模式?

Sté*_*las 18 awk

工具sedawk或一次perl -n处理他们的输入一条记录,默认情况下记录

有些,比如awkwith RS,GNU sedwith-zperlwith-0ooo可以通过选择不同的记录分隔符来改变记录的类型。

perl -n可以使整个输入(通过多个文件时每个单独的文件)成为带有选项的单个记录-0777(或-0后跟任何大于 0377 的八进制数,777 是规范的)。这就是他们所说的啜饮模式

可以用awk'sRS或任何其他机制完成类似的事情吗?在哪里awk处理每个文件内容作为一个整体,而不是每个文件的每一

Sté*_*las 18

您可以根据是awk将其RS视为单个字符(如传统awk实现)还是作为正则表达式(likegawkmawkdo)来采取不同的方法。空文件也很难被考虑,因为awk往往会跳过它们。

gawkmawk或其它awk实施方案中,其中RS可以是正规表达式。

在这些实现中(对于mawk,请注意某些操作系统(例如 Debian)提供了一个非常旧的版本,而不是由 @ThomasDickey 维护的现代版本),如果RS包含单个字符,则记录分隔符是该字符,或者awkRS为空时进入段落模式,否则视为RS正则表达式。

解决方案是使用不可能匹配的正则表达式。有些人会想到x^$xx在开始之前或结束之后)。然而,有些(尤其是gawk)比其他的更贵。到目前为止,我发现这^$是最有效的一种。它只能匹配一个空的输入,然后就没有什么可以匹配的了。

所以我们可以这样做:

awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Run Code Online (Sandbox Code Playgroud)

但需要注意的是,它会跳过空文件(与 相反perl -0777 -n)。GNU 可以awk通过将代码放在ENDFILE语句中来解决这个问题。但是我们还需要$0在 BEGINFILE 语句中重置,否则在处理空文件后它不会被重置:

gawk -v RS='^$' '
   BEGINFILE{$0 = ""}
   ENDFILE{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Run Code Online (Sandbox Code Playgroud)

传统awk实现,POSIXawk

在那些中,RS只是一个字符,它们没有BEGINFILE/ ENDFILE,它们没有RT变量,它们通常也无法处理 NUL 字符。

你会认为 usingRS='\0'可以工作,因为无论如何他们无法处理包含 NUL 字节的输入,但不,RS='\0'在传统实现中被视为RS=,这是段落模式。

一种解决方案是使用不太可能在输入中找到的字符,例如\1. 在多字节字符语言环境中,您甚至可以将其设置为不太可能发生的字节序列,因为它们形成未分配的字符或非字符,如$'\U10FFFE'UTF-8 语言环境。虽然不是真的万无一失,但你也有空文件的问题。

另一种解决方案是将整个输入存储在一个变量中,并在最后的 END 语句中进行处理。这意味着您一次只能处理一个文件:

awk '{content = content $0 RS}
     END{$0 = content
       printf "%s: <%s>\n", FILENAME, $0
     }' file
Run Code Online (Sandbox Code Playgroud)

这相当于sed's:

sed '
  :1
  $!{
   N;b1
  }
  ...' file1
Run Code Online (Sandbox Code Playgroud)

这种方法的另一个问题是,如果文件没有以换行符结尾(并且不为空),则仍然会$0在末尾任意添加一个(使用gawk,您可以通过使用RT而不是RS在上面的代码)。一个优点是您确实在NR/ 中记录了文件中的行数FNR

要一次处理多个文件,一种方法是在一个BEGIN语句中手动读取所有文件(这里假设是 POSIX awk,而不是 /bin/awk带有 70 年代 API 的 Solaris ):

awk -v RS='^$' '{printf "%s: <%s>\n", FILENAME, $0}' file1 file2...
Run Code Online (Sandbox Code Playgroud)

关于尾随换行符的相同警告。那个优点是能够处理包含=字符的文件名。

  • 尝试全部输入可能会遇到一些限制...传统的 awk 显然有(有?)一行上 99 个字段的限制...所以您可能还需要使用不同的 FS 来避免该限制,但您可能一行的总长度(或整个事物,如果你设法将其全部放在一行上)的总长度也有限制吗? (2认同)