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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17099860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:12:59  来源:igfitidea点击:

Why can't you use cat to read a file line by line where each line has delimiters

linuxbashfor-loopcat

提问by Classified

I have a text file that contains something like this:

我有一个包含以下内容的文本文件:

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma

I wrote a script

我写了一个脚本

for i in `cat file`
do
   echo $i
done

For some reason, the output of the script doesn't output the file line by line but breaks it off at the commas, as well as the newline. Why is cat or "for blah in cat xyz" doing this and how can I make it NOT do this? I know I can use a

出于某种原因,脚本的输出不会逐行输出文件,而是在逗号和换行符处将其断开。为什么 cat 或“for blah in cat xyz”这样做,我怎样才能让它不这样做?我知道我可以使用

while read line
do
   blah balh blah
done < file

but I want to know why cat or the "for blah in" is doing this to further my understanding of unix commands. Cat's man page didn't help me and looking at for or looping in the bash manual didn't yield any answers (http://www.gnu.org/software/bash/manual/bashref.html). Thanks in advance for your help.

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

采纳答案by Jonathan Leffler

The problem is not in cat, nor in the forloop per se; it is in the use of back quotes. When you write either:

问题不在于cat,也不在于for循环本身;它是在使用反引号。当你写:

for i in `cat file`

or (better):

或更好):

for i in $(cat file)

or (in bash):

或(在bash):

for i in $(<file)

the shell executes the command and captures the output as a string, separating the words at the characters in $IFS. If you want lines input to $i, you either have to fiddle with IFSor use the whileloop. The whileloop is better if there's any danger that the files processed will be large; it doesn't have to read the whole file into memory all at once, unlike the versions using $(...).

shell 执行命令并将输出捕获为字符串,将$IFS. 如果您希望将行输入到$i,则必须摆弄IFS或使用while循环。该while循环是更好,如果有任何危险,即处理的文件会很大; 与使用$(...).

IFS='
'
for i in $(<file)
do echo "$i"
done

The quotes around the "$i"are generally a good idea. In this context, with the modified $IFS, it actually isn't critical, but good habits are good habits even so. It matters in the following script:

周围的引号"$i"通常是一个好主意。在这种情况下,经过修改$IFS,其实并不重要,但好习惯就是好习惯。它在以下脚本中很重要:

old="$IFS"
IFS='
'
for i in $(<file)
do
   (
   IFS="$old"
   echo "$i"
   )
done

when the data file contains multiple spaces between words:

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

$ cat file
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$ 

Output:

输出:

$ sh bq.sh
abc                  123,         comma
the   quick   brown   fox
jumped   over   the   lazy   dog
comma,   comma
$

Without the double quotes:

没有双引号:

$ 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
$

回答by Sudheej

IFS - Internal field separator can be set to get what you want.

IFS - 可以设置内部字段分隔符以获得您想要的。

To read a whole line at once, use: IFS=""

要一次读取整行,请使用:IFS=""

回答by Dan675

the for loop coupled with a change of the internal field separator(IFS) will read file as intended

for 循环加上内部字段分隔符(IFS)的更改将按预期读取文件

for an input

对于输入

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma

For loop coupled with an IFS change

For 循环加上 IFS 更改

old_IFS=$IFS
IFS=$'\n'
for i in `cat file`
do
        echo $i
done
IFS=$old_IFS

results in

结果是

abc 123, comma
the quick brown fox
jumped over the lazy dog
comma, comma

回答by cforbish

You can use IFSvariable to specific you want a newline as the field separator:

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

IFS=$'\n'
for i in `cat file`
do
   echo $i
done

回答by user2954660

cat filename | while read i
do
    echo $i
done