为什么不能使用cat逐行读取文件,其中每行都有分隔符

Cla*_*ied 15 linux bash for-loop cat

我有一个包含这样的文本文件:

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
Run Code Online (Sandbox Code Playgroud)

我写了一个剧本

for i in `cat file`
do
   echo $i
done
Run Code Online (Sandbox Code Playgroud)

由于某种原因,脚本的输出不会逐行输出文件,而是在逗号和换行符处将其分开.为什么猫或"为了等待cat xyz"这样做,我怎么能不这样做呢?我知道我可以使用

while read line
do
   blah balh blah
done < file
Run Code Online (Sandbox Code Playgroud)

但我想知道为什么cat或"for blah in"这样做是为了进一步理解unix命令.Cat的手册页对我没有帮助,并且在bash手册中查找或循环没有产生任何答案(http://www.gnu.org/software/bash/manual/bashref.html).在此先感谢您的帮助.

Jon*_*ler 19

这个问题是不是在cat,也不在for环本身; 它是在使用后引号.你写的时候:

for i in `cat file`
Run Code Online (Sandbox Code Playgroud)

或更好):

for i in $(cat file)
Run Code Online (Sandbox Code Playgroud)

或(in bash):

for i in $(<file)
Run Code Online (Sandbox Code Playgroud)

shell执行命令并将输出捕获为字符串,将字符分隔为$IFS.如果你想要输入行$i,你要么必须摆弄IFS或使用while循环.该while循环是更好,如果有任何危险,即处理的文件会很大; 与使用的版本不同,它不必一次将整个文件读入内存$(...).

IFS='
'
for i in $(<file)
do echo "$i"
done
Run Code Online (Sandbox Code Playgroud)

周围的报价"$i"通常是一个好主意.在这种情况下,通过修改$IFS,它实际上并不重要,但良好的习惯即使如此也是良好的习惯.它在以下脚本中很重要:

old="$IFS"
IFS='
'
for i in $(<file)
do
   (
   IFS="$old"
   echo "$i"
   )
done
Run Code Online (Sandbox Code Playgroud)

当数据文件在单词之间包含多个空格时:

$ cat file
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$ 
Run Code Online (Sandbox Code Playgroud)

输出:

$ sh bq.sh
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$
Run Code Online (Sandbox Code Playgroud)

没有双引号:

$ cat bq.sh
old="$IFS"
IFS='
'
for i in $(<file)
do
   (
   IFS="$old"
   echo $i
   )
done
$ sh bq.sh
abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma
$
Run Code Online (Sandbox Code Playgroud)

  • IFS的默认值是(使用一连串的bash讲话)`$'\ t \ n'`; 也就是说,它由空白,制表符,换行符组成。这可能会改变您的分析。我相信,当您说“在逗号处断开”时,是指它在逗号后的空格处断开,这与包含空白(以及制表符和换行符)的IFS一致。 (2认同)

小智 7

cat filename | while read i
do
    echo $i
done
Run Code Online (Sandbox Code Playgroud)


cfo*_*ish 6

您可以使用IFS变量来特定您想要换行作为字段分隔符:

IFS=$'\n'
for i in `cat file`
do
   echo $i
done
Run Code Online (Sandbox Code Playgroud)

  • 不安全——你已经阻止了字符串分割,但没有阻止全局扩展。如果一行包含“*”,则在回显期间该行将扩展为当前目录中的名称列表。 (2认同)