使用Bash逐行读取并保留空间


76

当我使用“ cat test.file”时,它将显示

1
 2
  3
   4

当我使用Bash文件时,

cat test.file |
while read data
do
    echo "$data"
done

它会显示

1
2
3
4

我怎样才能像原始测试文件一样得到结果?


可以找到有用的脚本行来在stdio之前添加行号:{ i=0; while read; do i=$(dc 1 $i + p); printf "%4 d $REPLY\n" $i; done; }它与旧版SH兼容。
kyb

Answers:


117
IFS=''
cat test.file |
while read data
do
    echo "$data"
done

我意识到您可能已经从确实需要管道的东西简化了示例,但是在其他人说之前:

IFS=''
while read data; do
    echo "$data"
done < test.file

1
因为脚本正在每行读取一个变量,所以无论如何,数据中的任何空格(在第一个非空白之后)都将保留。但是空的IFS保留前导空格(以ksh和bash表示)。
乔纳森·莱夫勒

27
这是一个您可以写作的地方while IFS= read data; ...
glenn jackman 2011年

@glennjackman我正在开始尝试export IFS...,很好,我读过你的小费!
Aquarius Power

10
您可能要使用IFS= read -r line以避免解释反斜杠。
Lekensteyn 2014年

28

实际上,如果您不为“ read”调用提供参数,则read将设置一个名为$ REPLY的默认变量,该变量将保留空白。因此,您可以执行以下操作:

$ cat test.file | while read; do echo "$REPLY"; done

1
这个答案促使我仔细阅读的文档read
大卫·卡伦

3
请注意,如果您\n在源文件(即源代码)中有任何反斜杠转义的字符,read请将其转换为just n。使用read -r以防止这一点。
jdgregson

1
请注意,该$REPLY解决方案不适用于ZSH,但是该IFS= read解决方案适用于ZSH和Bash。
ntc2

4

只是为了补充DigitalRoss的响应。

对于只想为此命令更改IFS的情况,可以使用花括号。如果这样做,则仅在块内部更改IFS的值。像这样:

echo '
  word1
  word2' |  { IFS='' ; while read line ; do echo "$line" check ; done ; }

输出将是(保留空格):

  word1 check
  word2 check

即使未设置IFS已经解决了这个特定示例,您仍然应该引用"$line"。在一个真实的示例中,该值仍可以包含shell通配符,而不能包含通配符。
三胞胎2015年

1
错误的,太无礼了! 使用IFS='' read -r line,而不是! 在您的示例中,Pipe{..}在子外壳中运行!像IFS=' '; ( IFS='' ); echo "=$IFS="哪个打印= =(请注意SPC)。对比IFS=' '; { IFS=''; }; echo "=$IFS="打印==(来自的IFS {..})。但是,我还是建议:fullread() { local IFS=''; read -r $1; }IFS='' read -r line(没有;' between IFS =''`和read。在shellVAR=val cmd args..中,您仅需更改一条命令的环境(这也适用于内置命令read,也是如此)
。– Tino

1
我不确定我是否会跟随,蒂诺。尝试cat -etv <<<"$IFS" ; echo word1 | { IFS=''; cat -etv <<<"$IFS" ; } ; cat -etv <<<"$IFS" ;。子外壳程序没有像我期望的那样更改块外的IFS。你能详细说明吗?
diogovk

2

也许IFS是其他人所说的重点。您只需IFS=while和之间添加read

cat test.file | 
while IFS= read data 
 do echo "$data"
 done

并且不要忘记的引号$data,否则echo会缩小空格。

但是正如Joshua Davies所提到的,您可能更喜欢使用预定义的变量$REPLY


0

read data将通过IFS分割数据,通常为“ \ t \ n”。这将为您保留空白:

var=$(cat test.file)
echo "$var"

0

或者,使用一个好的文件解析工具,例如AWK

awk '{
  # Do your stuff
  print 
}' file
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.