读-N和IFS

时间:2015-08-23 11:22:28

标签: bash ifs

根据手册页中的“阅读-N”说明:

-N nchars仅在读取NCHARS字符后返回,除非遇到EOF或读取超时,忽略任何分隔符

但是,在回答以下命令时:

$ 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<<<
>>>
<<<

空格和换行符已正确存储在变量中。

所以,似乎分隔符在“read”或“while”命令中仍有一些处理,我不明白。

我们可以将这些结果与使用“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<<<
>>><<<

3 个答案:

答案 0 :(得分:4)

这是POSIX行为。分配给变量时,应剥离IFS字符:结果应分割成字段,如shell中的参数扩展结果(当然,-n和-N不是POSIX)。

这是由read源代码注释产生的:

/* This code implements the Posix.2 spec for splitting the words
     read and assigning them to variables. */
  orig_input_string = input_string;

  /* Remove IFS white space at the beginning of the input string.  If
     $IFS is null, no field splitting is performed. */

答案 1 :(得分:3)

在我看来,在使用选项-N时,read的行为在

时有所不同
  • 阅读分隔符作为输入
  • 将分隔符分配给变量

当它读取一个字符时,分隔符的处理方式与非分隔符相同,read将对它们进行计数。但是,当read分配分隔符时,它会认为如果读取输入是分隔符,如果它是分隔符,则它会为相应的变量赋予空值。

因此,IFS=将改变为变量分配空格的行为,并将空格分配给c而不是空。

答案 2 :(得分:2)

使用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 

在第一种情况下,0x0a和空格字符的内置读取返回空字符串,因为字符在默认IFS中,IFS中的字符在输出中被忽略,原因在于cdarke&回答。

(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

在这种情况下,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 

这给出与case(1)相同的输出,尽管语义有点不同:0x0a和空格字符的内置读取返回空字符串,因为(i)这两个字符在默认的IFS和(ii)读取内置的-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

在这里我们观察到-n和-N选项之间的区别:使用-n选项,换行特意处理读取内置并删除换行符,因此从IFS中排除0x0a并不# 39; t有机会将其传递给局部变量c