gawk RS 仅在行首与 ^
gawk RS only at beginning of line with ^
假设我有多行记录,=
作为记录分隔符,但前提是 =
是一行的开头:
$ cat file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
= record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
= final record 3, field 1
record 3, field 2
我想将与此类似的文件分成由 ^=[ \t]
分隔的记录和由 \n
分隔的字段。
我试过了:
$ gawk -v RS="^=[ \t]" -v FS="\n" '{printf "%s\n--- NF=%s, NR=%s ---\n", [=11=], NF, FNR}' file
但这会导致:
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
= record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
= final record 3, field 1
record 3, field 2
--- NF=9, NR=1 ---
即 ^
不能像我期望的那样作为行的开头。
我知道我能做到:
$ gawk -v RS="\n=[ \t]" -v FS="\n" '{printf "%s\nNF=%s, NR=%s\n", [=13=], NF, FNR}'
但这感觉就像 Unix / Windows 行分隔符的问题。它还有一个额外的 \n
附加到最终记录
我可以使用 sed
将 ^=[ \t]
替换为额外的 \n
然后在段落模式中使用 gawk
:
$ sed 's/^=[ \t]/\
/' file | gawk -v RS="" -v FS="\n" '{printf "%s\n--- NF=%s, NR=%s ---\n", [=14=], NF, FNR}'
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=2, NR=3 ---
正是我要找的东西。
问题:有没有办法在 RS
中使用 ^
在 gawk 中用多行记录指示 'start of the line',这样我就不必通过 sed
?我想我正在寻找 gawk
.
中 PCRE 正则表达式中 m
标志的等价物
我不知道这是否有所不同,但我发现在 BEGIN 子句中执行此操作稍微容易一些:
awk 'BEGIN {RS = "\n= "; FS = "\n"} {printf "%s\n--- NF=%s, NR=%s ---\n", [=10=], NF, FNR}' records
这给出了结果:
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=3, NR=3 ---
不需要解释,因为它实际上什么也没做,只是稍微重新表述了您已经做过的事情。看起来怎么样?
据我所知,^ 的问题在于本身没有 "lines"。有记载。我可能是错的,但我认为 "start of line" 概念与这种情况无关。 "Start of field" 将是,或 "start of record",尽管后者只是类似于:
[=12=] ~ /^chars/
但是,我对 awk 这部分的内部工作原理知之甚少,所以我欢迎对它的教育。
你可以通过检查最后一个字段来避免最后一条记录额外的新行
$ awk -F'\n' -v RS='\n=[ \t]' -v OFS='\n' '{NF-=$NF=="";
print [=10=], "---NF="NF ", ---NR="FNR}' file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
---NF=3, ---NR=1
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
---NF=3, ---NR=2
final record 3, field 1
record 3, field 2
---NF=2, ---NR=3
^
表示 start of string
,而不是 start of line
。没有 start of line
字符,只有回车 return(\r
= return 光标到行首)和换行(\n
= 删除光标移到下一行)根据 tool/OS 一起或单独用于表示 end of line
又名 newline
的字符。 Windows 工具倾向于使用 \r\n
表示 newline
而 UNIX 单独使用 \n
这就是为什么 \n
通常被称为 newline character
在 UNIX 中。
许多工具,例如sed
和 grep
(默认情况下 awk
)一次只读取 1 行,因此它们的输入缓冲区一次只包含一行,因此在该上下文中 start of string
与 start of line
相同,这就是为什么您经常听到 ^
被称为 start of line
字符,而通常情况下它不是。类似地,$
是 end of string
字符,而不是通常提到的 end of line
字符,但在某些工具用于字符串输入缓冲区的上下文中时,可用于表示行尾reading/populating 一次一行。
这意味着如果您的工具不是一次读取一行,那么在 UNIX 文件中匹配行首字符 X
的正则表达式实际上是:
(^|\n)X
一行的结尾是:
X(\n|$)
但请注意,如果存在,这也是 matching/consuming 换行字符。
在 Windows 中将上面的 \n
更改为 \r\n
并在两者中工作,您可以使用 \r?\n
除非您的文件是在 Windows 上创建的并且可以包含换行中线,例如从 Excel 导出的 CSV 可能看起来像
field1,"field2 part a\nfield2 part b",field3\r\n
其中 \n
和 \r
当然是字面意思。在那种情况下,您不希望独立的 \n
中场被误解为换行符。
试试这个(gawk-only 由于多字符 RS
和 \s
shorthand for [[:space:]]
):
$ awk -v RS='\n(=\s*|$)' -F'\n' '{printf "%s\n--- NF=%s, NR=%s ---\n", [=13=], NF, FNR}' file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=2, NR=3 ---
假设我有多行记录,=
作为记录分隔符,但前提是 =
是一行的开头:
$ cat file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
= record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
= final record 3, field 1
record 3, field 2
我想将与此类似的文件分成由 ^=[ \t]
分隔的记录和由 \n
分隔的字段。
我试过了:
$ gawk -v RS="^=[ \t]" -v FS="\n" '{printf "%s\n--- NF=%s, NR=%s ---\n", [=11=], NF, FNR}' file
但这会导致:
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
= record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
= final record 3, field 1
record 3, field 2
--- NF=9, NR=1 ---
即 ^
不能像我期望的那样作为行的开头。
我知道我能做到:
$ gawk -v RS="\n=[ \t]" -v FS="\n" '{printf "%s\nNF=%s, NR=%s\n", [=13=], NF, FNR}'
但这感觉就像 Unix / Windows 行分隔符的问题。它还有一个额外的 \n
附加到最终记录
我可以使用 sed
将 ^=[ \t]
替换为额外的 \n
然后在段落模式中使用 gawk
:
$ sed 's/^=[ \t]/\
/' file | gawk -v RS="" -v FS="\n" '{printf "%s\n--- NF=%s, NR=%s ---\n", [=14=], NF, FNR}'
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=2, NR=3 ---
正是我要找的东西。
问题:有没有办法在 RS
中使用 ^
在 gawk 中用多行记录指示 'start of the line',这样我就不必通过 sed
?我想我正在寻找 gawk
.
m
标志的等价物
我不知道这是否有所不同,但我发现在 BEGIN 子句中执行此操作稍微容易一些:
awk 'BEGIN {RS = "\n= "; FS = "\n"} {printf "%s\n--- NF=%s, NR=%s ---\n", [=10=], NF, FNR}' records
这给出了结果:
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=3, NR=3 ---
不需要解释,因为它实际上什么也没做,只是稍微重新表述了您已经做过的事情。看起来怎么样?
据我所知,^ 的问题在于本身没有 "lines"。有记载。我可能是错的,但我认为 "start of line" 概念与这种情况无关。 "Start of field" 将是,或 "start of record",尽管后者只是类似于:
[=12=] ~ /^chars/
但是,我对 awk 这部分的内部工作原理知之甚少,所以我欢迎对它的教育。
你可以通过检查最后一个字段来避免最后一条记录额外的新行
$ awk -F'\n' -v RS='\n=[ \t]' -v OFS='\n' '{NF-=$NF=="";
print [=10=], "---NF="NF ", ---NR="FNR}' file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
---NF=3, ---NR=1
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
---NF=3, ---NR=2
final record 3, field 1
record 3, field 2
---NF=2, ---NR=3
^
表示 start of string
,而不是 start of line
。没有 start of line
字符,只有回车 return(\r
= return 光标到行首)和换行(\n
= 删除光标移到下一行)根据 tool/OS 一起或单独用于表示 end of line
又名 newline
的字符。 Windows 工具倾向于使用 \r\n
表示 newline
而 UNIX 单独使用 \n
这就是为什么 \n
通常被称为 newline character
在 UNIX 中。
许多工具,例如sed
和 grep
(默认情况下 awk
)一次只读取 1 行,因此它们的输入缓冲区一次只包含一行,因此在该上下文中 start of string
与 start of line
相同,这就是为什么您经常听到 ^
被称为 start of line
字符,而通常情况下它不是。类似地,$
是 end of string
字符,而不是通常提到的 end of line
字符,但在某些工具用于字符串输入缓冲区的上下文中时,可用于表示行尾reading/populating 一次一行。
这意味着如果您的工具不是一次读取一行,那么在 UNIX 文件中匹配行首字符 X
的正则表达式实际上是:
(^|\n)X
一行的结尾是:
X(\n|$)
但请注意,如果存在,这也是 matching/consuming 换行字符。
在 Windows 中将上面的 \n
更改为 \r\n
并在两者中工作,您可以使用 \r?\n
除非您的文件是在 Windows 上创建的并且可以包含换行中线,例如从 Excel 导出的 CSV 可能看起来像
field1,"field2 part a\nfield2 part b",field3\r\n
其中 \n
和 \r
当然是字面意思。在那种情况下,您不希望独立的 \n
中场被误解为换行符。
试试这个(gawk-only 由于多字符 RS
和 \s
shorthand for [[:space:]]
):
$ awk -v RS='\n(=\s*|$)' -F'\n' '{printf "%s\n--- NF=%s, NR=%s ---\n", [=13=], NF, FNR}' file
record 1, field 1
record 1, field 2 with a = in it
record 1, field 3
--- NF=3, NR=1 ---
record 2, field 1
record 2, field 2 also with a = in it
record 2, field 3
--- NF=3, NR=2 ---
final record 3, field 1
record 3, field 2
--- NF=2, NR=3 ---