Bash读取忽略前导空格

时间:2015-04-17 02:23:20

标签: bash

我的文件a.txt包含以下内容

    aaa
    bbb

当我执行以下脚本时:

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

生成的b.txt包含以下

aaa
bbb

可以看出,线条的前导空间已被删除。我怎样才能保留领先的空间?

2 个答案:

答案 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代替echoprintf的行为在某种程度上不可能在所有环境中都不一致,并且差异可能很难处理。另一方面,{{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