为什么 `awk 1 RS=, <<< "1,2"` 多写一行?
Why is `awk 1 RS=, <<< "1,2"` writing an extra new line?
我 一个问题,我在其中使用了一些 awk
技巧将逗号转换为换行:
awk 1 RS=, file
但是,我随后注意到这在输出的末尾引入了一个额外的新行:
$ cat a
1,2
$ awk 1 RS=, a
1
2
# one extra line
$ awk 1 RS=, <<< "1,2"
1
2
# one extra line
因为 1
是 {print [=18=]}
的简写,所以我决定看看发生了什么:
$ awk '{print [=12=], "hey"}' RS=, <<< "1,2"
1 hey
2
hey
所以是的,显然拆分已经完成,但由于某种原因,第二条记录包含在 2
后面跟一个新行。是的,awk
只看到两条记录:
$ awk '{print NR}' RS=, <<< "1,2"
1
2
对我来说这是有道理的,因为 echo
和 here-strings 在输出的末尾添加了这样的新行,而 printf
则没有。并且有效地与 printf:
一起工作
$ awk '{print [=14=], "hey"}' RS=, < <(printf "1,2")
1 hey
2 hey # no more lines after this
好的,我说:那只是追加到字符串末尾的新行的问题。
但后来...我发现情况并非总是如此,我的困惑变得更大:
$ awk '{print [=15=], "hey"}' <<< "1,2"
1,2 hey # no more lines after this
所以我的问题是:RS=,
做了什么导致追加这个额外的新行?
这是输入流中的换行符。
$ awk 1 RS=, < <(echo -n 1,2)
1
2
输出中不会有额外的换行符。但是,执行此操作的标准方法是使用 tr
$ tr ',' '\n' < file
比较
$ echo 1,2 | awk 1 RS=,
1
2
$ echo 1,2 | tr ',' '\n'
1
2
Awk 处理每条记录,自动从末尾删除记录分隔符。如果您将其更改为换行符以外的其他内容,这意味着它不会被删除,因此您最终会遇到这种行为。
你的 "record count" 是 2,即使你只有一个 ,
但在这个例子中它也是 2(希望不会让这更混乱!):
$ printf 'a\nb' | awk '{print NR}'
1
2
添加换行符的不是 awk,而是 <<<
。如果 shell 没有在您使用 <<<
指定的文本末尾添加终止换行符,那么结果将不是每个 POSIX 的文本 "file" 等依赖任何试图解析它的工具的未定义行为。
因此,当您编写 command <<< 'foo'
时,command
看到的不是 foo
,而是 foo\n
,因此在您的命令行中:
awk 1 RS=, <<< "1,2"
awk 看到的是 1,2\n
,当您将其拆分为 ,
处的记录时,您将获得 1
的第一条记录和 2\n
的第二条记录。
我 awk
技巧将逗号转换为换行:
awk 1 RS=, file
但是,我随后注意到这在输出的末尾引入了一个额外的新行:
$ cat a
1,2
$ awk 1 RS=, a
1
2
# one extra line
$ awk 1 RS=, <<< "1,2"
1
2
# one extra line
因为 1
是 {print [=18=]}
的简写,所以我决定看看发生了什么:
$ awk '{print [=12=], "hey"}' RS=, <<< "1,2"
1 hey
2
hey
所以是的,显然拆分已经完成,但由于某种原因,第二条记录包含在 2
后面跟一个新行。是的,awk
只看到两条记录:
$ awk '{print NR}' RS=, <<< "1,2"
1
2
对我来说这是有道理的,因为 echo
和 here-strings 在输出的末尾添加了这样的新行,而 printf
则没有。并且有效地与 printf:
$ awk '{print [=14=], "hey"}' RS=, < <(printf "1,2")
1 hey
2 hey # no more lines after this
好的,我说:那只是追加到字符串末尾的新行的问题。
但后来...我发现情况并非总是如此,我的困惑变得更大:
$ awk '{print [=15=], "hey"}' <<< "1,2"
1,2 hey # no more lines after this
所以我的问题是:RS=,
做了什么导致追加这个额外的新行?
这是输入流中的换行符。
$ awk 1 RS=, < <(echo -n 1,2)
1
2
输出中不会有额外的换行符。但是,执行此操作的标准方法是使用 tr
$ tr ',' '\n' < file
比较
$ echo 1,2 | awk 1 RS=,
1
2
$ echo 1,2 | tr ',' '\n'
1
2
Awk 处理每条记录,自动从末尾删除记录分隔符。如果您将其更改为换行符以外的其他内容,这意味着它不会被删除,因此您最终会遇到这种行为。
你的 "record count" 是 2,即使你只有一个 ,
但在这个例子中它也是 2(希望不会让这更混乱!):
$ printf 'a\nb' | awk '{print NR}'
1
2
添加换行符的不是 awk,而是 <<<
。如果 shell 没有在您使用 <<<
指定的文本末尾添加终止换行符,那么结果将不是每个 POSIX 的文本 "file" 等依赖任何试图解析它的工具的未定义行为。
因此,当您编写 command <<< 'foo'
时,command
看到的不是 foo
,而是 foo\n
,因此在您的命令行中:
awk 1 RS=, <<< "1,2"
awk 看到的是 1,2\n
,当您将其拆分为 ,
处的记录时,您将获得 1
的第一条记录和 2\n
的第二条记录。