2015-04-17 74 views
18

我有文件a.txt與以下內容巴什讀取線不讀前導空格

aaa 
    bbb 

當我執行下面的腳本:

while read line 
do 
    echo $line 
done <a.txt> b.txt 

產生b.txt包含以下

aaa 
bbb 

它可以看到,行的領先空間已被刪除。我怎樣才能保留領先的空間?

回答

27

這是覆蓋在上reading data line-by-line Bash的FAQ條目。

的讀命令修改每個線讀取;默認情況下,它將刪除所有前導和尾隨空白字符(空格和製表符或IFS中存在的任何空白字符)。如果沒有需要,IFS變量被清除:

# Exact lines, no trimming 
while IFS= read -r line; do 
    printf '%s\n' "$line" 
done < "$file" 

正如查爾斯·達菲正確地指出(我想通過關注IFS問題錯過了);如果你想在你的輸出中看到空格,你還需要在使用它時引用變量,否則shell會再次刪除空格。

一些有關在引用片段的其他差異說明比你原來的代碼。

-r參數用於read的用法在前面鏈接頁面頂部的單個句子中進行了說明。

讀取的-r選項可防止反斜槓解釋(通常用作反斜槓換行對,以在多行上繼續)。沒有這個選項,輸入中的反斜槓將被丟棄。您應該幾乎總是在讀取時使用-r選項。

至於使用printf代替echo存在的echo的行爲是有些不幸的是,在各種環境下,差異並不一致的可移植性可勁兒對付。另一方面,printf是一致的,可以完全穩健地使用。

+5

如果您不給'read'使用任何參數來保存輸入(依賴默認變量'REPLY'),則不會刪除空格,並且可以省略對「IFS」的修改。也就是說,'while read -r;做printf'%s \ n'「$ REPLY」;完成<「$ file」' – chepner

+1

@chepner有趣。我不知道這是爲什麼。 –

+2

我不確定;據我所知,似乎沒有記錄。如果您認爲這是有道理的,因爲零參數要求將行分割成零個字段,這意味着「IFS」沒有用處。 (假設你接受將一行分割成一個字段仍然是一個分裂,儘管是退化的)。無論如何,這是一種「bash」主義; POSIX'read'至少需要一個參數。 – chepner

9

有幾個問題在這裏:

  • 除非IFS被清除,read帶開頭和結尾的空白。
  • echo $line字符串拆分和全局擴展$line的內容,將其拆分爲單個單詞,然後將這些單詞作爲單個參數傳遞給echo命令。因此,即使在IFS時間read清除,echo $line仍然會丟棄開頭和結尾的空白,並改變單詞之間的空格運行到每一個空格字符。此外,僅包含字符*的行將被展開以包含文件名列表。
  • echo "$line"是顯著改善,但仍然不能正確處理值,如-n,它把作爲回聲說法本身。 printf '%s\n' "$line"會完全解決這個問題。
  • read而不-r對待反斜線作爲連續符而不是文本內容,使得它們將不會被包含在產生除非一倍向上逸出本身的值。

這樣:

while IFS= read -r line; do 
    printf '%s\n' "$line" 
done 
+0

很好的建議,但是雙字符序列'\ n'不會導致_newline_,導致_literal'n'_。相比之下,''''''''''''''''''''''''會使'read'讀取_following_行,並將其直接附加到當前行(放棄'\'和換行符)。任何其他字符之前的'\'都會被丟棄。 – mklement0

+2

另一種描述沒有'-r'的'read'行爲的方式:輸入被解析的方式與('POSIX)shell本身解析單個''''轉義字符的空白字符(例如,作爲一個參數列表),如http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_02_01 中所述,並基本上覆制到http://pubs.opengroup的read'的POSIX規範中。組織/ onlinepubs/9699919799 /公共事業/ read.html。 – mklement0

+2

謝謝 - 我要審查源文件,以確定如何最好地修改我答案的這一部分。 –