在这个bash循环中,IFS=做什么:' cat file |,而IFS= read -r line;做……做

时间:2022-09-18 20:21:39

I'm learning bash and I saw this construction:

我正在学习bash,我看到它的结构:

cat file | while IFS= read -r line;
do
    ...
done

Can anyone explain what IFS= do? I know it's input field sepereter, but it's being set to nothing?

有人能解释一下如果=做什么吗?我知道它是输入场sepereter,但它被设为零?

1 个解决方案

#1


26  

IFS does many things but you are asking about that particular loop.

IFS做了很多事情,但你问的是那个特定的循环。

The effect in that loop is to preserve leading and trailing white space in line. To illustrate, first observe with IFS set to nothing:

这个循环的效果是保持前导和后导的空白行。为了说明这一点,首先用if设为空进行观察:

$ echo " this   is a test " | while IFS= read -r line; do echo "=$line=" ; done
= this   is a test =

The line variable contains all the white space it received on its stdin. Now, consider the same statement with the default IFS:

line变量包含它在stdin上接收到的所有空白。现在,考虑使用默认IFS的相同语句:

$ echo " this   is a test " | while read -r line; do echo "=$line=" ; done
=this   is a test=

In this version, the white space internal to the line is still preserved. But, the leading and trailing white space have been removed.

在这个版本中,行内部的空白仍然保留。但是,前缘和后缘的空白已经被删除。

What does -r do in read -r?

The -r option prevents read from treating backslash as a special character.

-r选项防止将反斜杠视为特殊字符。

To illustrate, we use two echo commands that supply two lines to the while loop. Observe what happens with -r:

为了举例说明,我们使用两个echo命令为while循环提供两行。观察-r发生了什么:

$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read -r line; do echo "=$line=" ; done
=this \\ line is \=
=continued=

Now, observe what happens without -r:

现在,观察没有-r的情况:

$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read line; do echo "=$line=" ; done
=this \ line is continued=

Without -r, two changes happened. First, the double-backslash was converted to a single backslash. Second, the backslash on the end of the first line was interpreted as a line-continuation character and the two lines were merged into one.

没有-r,两个变化发生了。首先,双反斜杠被转换为单反斜杠。第二,第一行末尾的反斜杠被解释为行延续字符,两行合并为一行。

In sum, if you want backslashes in the input to have special meaning, don't use -r. If you want backslashes in the input to be taken as plain characters, then use -r.

总而言之,如果你想要回车在输入中有特殊的意义,不要使用-r。如果希望将输入中的反斜杠作为普通字符,则使用-r。

Multiple lines of input

Since read takes input one line at a time, IFS behaves affects each line of multiple line input in the same way that it affects single line input. -r behaves similarly with the exception that, without -r, multiple lines can be combined into one line using the trailing backslash as shown above.

因为read每次输入一行,所以IFS的行为会影响多行输入的每一行,就像它影响单行输入一样。-r的行为类似于一个例外,即如果没有-r,可以使用尾反斜杠将多行合并为一行。

The behavior with multiple line input, however, can be changed drastically using read's -d flag. -d changes the delimiter character that read uses to mark the end of an input line. For example, we can terminate lines with a tab character:

但是,使用read的-d标志可以改变多行输入的行为。-d更改read用来标记输入行结束的分隔符字符。例如,我们可以终止带有制表符的行:

$ echo $'line one \n line\t two \n line three\t ends here'
line one 
 line    two 
 line three      ends here
$ echo $'line one \n line\t two \n line three\t ends here' | while IFS= read -r -d$'\t' line; do echo "=$line=" ; done
=line one 
 line=
= two 
 line three=

Here, the $'...' construct was used to enter special characters like newline, \n and tab, \t. Observe that with -d$'\t', read divides its input into "lines" based on tab characters. Anything after the final tab is ignored.

在这里,美元的…构造用于输入特殊字符,如换行、\n和tab、\t。请注意,使用-d$'\t', read根据制表符将输入划分为“行”。最后一个选项卡之后的任何内容都将被忽略。

How to handle the most difficult file names

The most important use of the features described above is to process difficult file names. Since the one character that cannot appear in path/filenames is the null character, the null character can be used to separate a list of file names. As an example:

上面描述的特性最重要的用途是处理难处理的文件名。由于路径/文件名中不能出现的唯一字符是null字符,因此可以使用null字符分隔文件名列表。作为一个例子:

while IFS= read -r -d $'\0' file
do
    # do something to each file
done < <(find ~/music -type f -print0)

#1


26  

IFS does many things but you are asking about that particular loop.

IFS做了很多事情,但你问的是那个特定的循环。

The effect in that loop is to preserve leading and trailing white space in line. To illustrate, first observe with IFS set to nothing:

这个循环的效果是保持前导和后导的空白行。为了说明这一点,首先用if设为空进行观察:

$ echo " this   is a test " | while IFS= read -r line; do echo "=$line=" ; done
= this   is a test =

The line variable contains all the white space it received on its stdin. Now, consider the same statement with the default IFS:

line变量包含它在stdin上接收到的所有空白。现在,考虑使用默认IFS的相同语句:

$ echo " this   is a test " | while read -r line; do echo "=$line=" ; done
=this   is a test=

In this version, the white space internal to the line is still preserved. But, the leading and trailing white space have been removed.

在这个版本中,行内部的空白仍然保留。但是,前缘和后缘的空白已经被删除。

What does -r do in read -r?

The -r option prevents read from treating backslash as a special character.

-r选项防止将反斜杠视为特殊字符。

To illustrate, we use two echo commands that supply two lines to the while loop. Observe what happens with -r:

为了举例说明,我们使用两个echo命令为while循环提供两行。观察-r发生了什么:

$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read -r line; do echo "=$line=" ; done
=this \\ line is \=
=continued=

Now, observe what happens without -r:

现在,观察没有-r的情况:

$ { echo 'this \\ line is \' ; echo 'continued'; } | while IFS= read line; do echo "=$line=" ; done
=this \ line is continued=

Without -r, two changes happened. First, the double-backslash was converted to a single backslash. Second, the backslash on the end of the first line was interpreted as a line-continuation character and the two lines were merged into one.

没有-r,两个变化发生了。首先,双反斜杠被转换为单反斜杠。第二,第一行末尾的反斜杠被解释为行延续字符,两行合并为一行。

In sum, if you want backslashes in the input to have special meaning, don't use -r. If you want backslashes in the input to be taken as plain characters, then use -r.

总而言之,如果你想要回车在输入中有特殊的意义,不要使用-r。如果希望将输入中的反斜杠作为普通字符,则使用-r。

Multiple lines of input

Since read takes input one line at a time, IFS behaves affects each line of multiple line input in the same way that it affects single line input. -r behaves similarly with the exception that, without -r, multiple lines can be combined into one line using the trailing backslash as shown above.

因为read每次输入一行,所以IFS的行为会影响多行输入的每一行,就像它影响单行输入一样。-r的行为类似于一个例外,即如果没有-r,可以使用尾反斜杠将多行合并为一行。

The behavior with multiple line input, however, can be changed drastically using read's -d flag. -d changes the delimiter character that read uses to mark the end of an input line. For example, we can terminate lines with a tab character:

但是,使用read的-d标志可以改变多行输入的行为。-d更改read用来标记输入行结束的分隔符字符。例如,我们可以终止带有制表符的行:

$ echo $'line one \n line\t two \n line three\t ends here'
line one 
 line    two 
 line three      ends here
$ echo $'line one \n line\t two \n line three\t ends here' | while IFS= read -r -d$'\t' line; do echo "=$line=" ; done
=line one 
 line=
= two 
 line three=

Here, the $'...' construct was used to enter special characters like newline, \n and tab, \t. Observe that with -d$'\t', read divides its input into "lines" based on tab characters. Anything after the final tab is ignored.

在这里,美元的…构造用于输入特殊字符,如换行、\n和tab、\t。请注意,使用-d$'\t', read根据制表符将输入划分为“行”。最后一个选项卡之后的任何内容都将被忽略。

How to handle the most difficult file names

The most important use of the features described above is to process difficult file names. Since the one character that cannot appear in path/filenames is the null character, the null character can be used to separate a list of file names. As an example:

上面描述的特性最重要的用途是处理难处理的文件名。由于路径/文件名中不能出现的唯一字符是null字符,因此可以使用null字符分隔文件名列表。作为一个例子:

while IFS= read -r -d $'\0' file
do
    # do something to each file
done < <(find ~/music -type f -print0)