我的文件a.txt
包含以下内容
aaa
bbb
当我执行以下脚本时:
while read line
do
echo $line
done < a.txt > b.txt
生成的b.txt
包含以下
aaa
bbb
可以看出,线条的前导空间已被删除。我怎样才能保留领先的空间?
答案 0 :(得分:37)
reading data line-by-line上的Bash常见问题解答条目对此进行了介绍。
读取命令修改每行读取;默认情况下,它会删除所有前导和尾随空白字符(空格和制表符,或IFS中存在的任何空格字符)。如果不需要,则必须清除IFS变量:
# Exact lines, no trimming while IFS= read -r line; do printf '%s\n' "$line" done < "$file"
正如查尔斯达菲正确地指出的那样(我关注IFS
问题我错过了);如果你想在输出中看到空格,你还需要在使用它时引用变量,否则shell将再次删除空格。
注释与原始代码相比,引用代码段中的其他一些差异。
-r
read
参数对printf
的使用将在之前链接页面顶部的单个句子中进行介绍。
读取的-r选项可防止反斜杠解释(通常用作反斜杠换行符对,以继续多行)。如果没有此选项,输入中的任何反斜杠都将被丢弃。您应该几乎总是将-r选项与read。一起使用。
至于使用echo
代替echo
,printf
的行为在某种程度上不可能在所有环境中都不一致,并且差异可能很难处理。另一方面,{{1}}是一致的,可以完全稳健地使用。
答案 1 :(得分:12)
这里有几个问题:
IFS
,否则read
会删除前导和尾随空格。echo $line
string-splits和glob-expands $line
的内容,将其分解为单个单词,并将这些单词作为单独的参数传递给echo
命令。因此,即使IFS在read
时间被清除,echo $line
仍然会丢弃前导空格和尾随空格,并且将单词之间的空格更改为单个空格字符。此外,仅包含字符*
的行将展开以包含文件名列表。echo "$line"
是一项重大改进,但仍然无法正确处理-n
等值,它将其视为一个echo参数。 printf '%s\n' "$line"
会完全解决这个问题。read
没有-r
将反斜杠视为连续字符而不是文字内容,这样它们就不会被包含在生成的值中,除非双倍自我逃避。因此:
while IFS= read -r line; do
printf '%s\n' "$line"
done