2015-08-23 48 views
4

根據手冊「讀-N」描述:閱讀-N和IFS

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

空間和新行已被正確存儲在變量。

所以,似乎分隔符仍具有「讀取」或「而」命令,我不明白一些處理。

我們可以比較這些結果與用「讀-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<<< 
>>><<< 

回答

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的ans中解釋的原因WER。

(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 

在這種情況下,內置將匹配每個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 

這給出只是輸出作爲殼體(1)相同,雖然語義是有點不同:內置兩個0x0a和所述空間中的讀取字符返回空字符串,因爲(i)這兩個字符都在默認的IFS中;(ii)讀內置的-n選項在任何情況下都不通過尾隨0x0a字符

(4)With空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沒有一個機會讓它傳遞給當地變量c

+0

優秀的解釋,但仍然是一個開放點,案例(4)中的換行符,即使不屬於IFS,也以與空間不同的方式處理。也就是說,我認爲(3)我們不能說「0x0a,空格字符返回空字符串,因爲這兩個字符都在默認的IFS中」。 –

+0

@pasabaporaqui - 你說得很對:-n開關的語義意味着IFO中的'0x0a'是多餘的。我已經改變了討論,以便明確這個冗餘。 –

+0

完美,只是在案例(2)中的編輯評論:「IFS未定」應該是「IFS空」。 –

3

在我看來之前被讀取,同時使用選項-Nread的行爲是不同的,當

  • 閱讀分隔符輸入
  • 分配是分隔符爲變量

當它讀一個字符,分隔符將其視爲等同於非分隔符和read將盡數。但是,當read正在分配分隔符時,它認爲如果讀取輸入是分隔符,如果它是分隔符,則它將空分配給對應的變量。

因此,IFS=將更改將空白分配給變量的行爲,並導致將空間分配給c而不是空值。

4

這是POSIX行爲。當分配給一個變量時,IFS字符應該被剝離:結果應該被拆分成字段,就像在參數擴展結果(當然,-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. */ 
+0

非常有趣。只有在「while IFS = read -n1 c」的情況下將換行符轉換爲空字符串似乎很難與這些描述相匹配。我期望或「循環結束」,並沒有打印或換行。事實上,這種情況是-n1和-N1測試之間唯一的區別。 –

+0

換行符是默認'IFS'設置的一部分,換句話說,它是一個分隔符。我沒有看到任何不一致。 – cdarke

+0

是的,但是默認的IFS(未設置的IFS)不同於空的IFS,也就是在這個集合中使用的IFS。而且,空格也在默認的分隔符集中,並且在這個測試中以不同的方式處理。 –

1

read不能決定一個字母是分隔符(忽略它),直到它已經讀出的字符,並read必須分配一些價值c,即使這個值是空字符串。當一個分隔符讀取,隨後丟棄的c值必須設置爲東西,所以它被賦予空字符串。

這與沒有-n/-N選項時使用的read一致;只有在之後纔會讀取分隔符,並且如果它們不需要設置提供的參數值。最簡單的情況是,當你沒有提供任何參數read

$ read <<< " a b c " 
$ echo ">>>$REPLY<<<" 
>>> a b c <<< 

憑藉獨顯的說法,開頭和結尾的分隔符被剝離:

$ read line <<< " a b c " 
$ echo ">>>$line<<<" 
>>>a b c<<< 

隨着2個參數,第一個分隔符一旦被讀取就被忽略。第二個被保留,因爲字符串只需要被分成兩個單詞來填充提供的參數。

$ read field1 field2 <<< " a b c """ 
$ echo ">>>$field1<<<" 
>>>a<<< 
$ echo ">>>$field2<<<" 
>>>b c<<<