根据手册页中的“读-N”描述:
-N nchars仅在完全读取了NCHARS个字符后才返回,除非遇到EOF或读取超时,而忽略任何定界符
但是,请回答以下命令:
$ echo 'a b' | while read -N1 c; do echo ">>>$c<<<"; done
>>>a<<<
>>><<<
>>>b<<<
>>><<<
Run Code Online (Sandbox Code Playgroud)
在命令中,空格和换行符都已转换为空字符串,而在命令中:
$ echo 'a b' | while IFS= read -N1 c; do echo ">>>$c<<<"; done
>>>a<<<
>>> <<<
>>>b<<<
>>>
<<<
Run Code Online (Sandbox Code Playgroud)
空格和换行符已正确存储在变量中。
因此,似乎分隔符在“读取”或“同时”命令中仍有一些处理,我不理解。
我们可以将这些结果与使用“ read -n”的结果进行比较,该手册描述为:
-n nchars在读取NCHARS字符后返回而不是等待换行符,但是如果在分隔符之前读取的字符少于NCHARS,则使用分隔符
$ echo 'a b' | while read -n1 c; do echo ">>>$c<<<"; done
>>>a<<<
>>><<<
>>>b<<<
>>><<<
$ echo 'a b' | while IFS= read -n1 c; do echo ">>>$c<<<"; done
>>>a<<<
>>> <<<
>>>b<<<
>>><<<
Run Code Online (Sandbox Code Playgroud)
使用hexdump使我们能够准确地看到组成输出的字符,因此稍微改变您的查询可能会有所帮助:
(1) 使用普通 IFS 并使用 -N 选项
$ (echo 'a b' | while read -N1 c; do c="$c<"; echo -n "$c"; done | hexdump -C)
00000000 61 3c 3c 62 3c 3c |a<<b<<|
00000006
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,两者的 read 内置0x0a函数和空格字符都会返回空字符串,因为字符位于默认的 IFS 中,并且由于 cdarke 的答案中解释的原因,IFS 中的字符在输出中被忽略。
(2) 使用空 IFS 和 -N 选项
$ (IFS=""; echo 'a b' | while read -N1 c; do c="$c<"; echo -n "$c"; done | hexdump -C)
00000000 61 3c 20 3c 62 3c 0a 3c |a< <b<.<|
00000008
Run Code Online (Sandbox Code Playgroud)
在这种情况下, read 内置函数将匹配 echo 命令输出的四个字符中的每一个,并且0x0a在输出中可以看到两个字符和一个空格,因为使用空的 IFS 可以将读取的字符分配给局部变量c。
(3) 使用普通 IFS 和 -n 选项
$ (echo 'a b' | while read -n1 c; do c="$c<"; echo -n "$c"; done | hexdump -C)
00000000 61 3c 3c 62 3c 3c |a<<b<<|
00000006
Run Code Online (Sandbox Code Playgroud)
这给出了与情况 (1) 相同的输出,尽管语义有点不同:两者的 read 内置函数0x0a和空格字符返回空字符串,因为 (i) 这两个字符都在默认的 IFS 中并且 (ii ) read 内置命令的 -n 选项在任何情况下都不会传递尾随0x0a字符
(4) 使用空 IFS 和 -n 选项
$ (IFS=""; echo 'a b' | while read -n1 c; do c="$c<"; echo -n "$c"; done | hexdump -C)
00000000 61 3c 20 3c 62 3c 3c |a< <b<<|
00000007
Run Code Online (Sandbox Code Playgroud)
在这里,我们观察到 -n 和 -N 选项之间的差异来读取:使用 -n 选项时,换行符会被内置的 read 特殊处理并删除,因此从 IFS 中排除0x0a没有机会允许它被传递给局部变量c。