bash 根据“IFS”变量的值改变其行为

use*_*935 18 shell bash

当我将IFS变量设置为一个空格时,bash将多个空格视为一个空格(myprogram是一个打印它接收到的命令行参数的程序):

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world
Run Code Online (Sandbox Code Playgroud)

但是当我将IFS变量设置为逗号时,bash不会将多个逗号视为一个逗号:

IFS=","
x="hello,,,hi,,,world"
./myprogram $x
argv[1] = hello
argv[2] = 
argv[3] = 
argv[4] = hi
argv[5] = 
argv[6] = 
argv[7] = world
Run Code Online (Sandbox Code Playgroud)

这是为什么?

Joh*_*024 21

这记录在man bash. IFS 中任何非空格字符的单次出现都会对字段进行分隔。

来自man bash

Shell 将 IFS 的每个字符视为分隔符,并使用这些字符作为字段终止符将其他扩展的结果拆分为单词。如果IFS没有设置,或者它的值是完全<space><tab><newline>,默认值,然后序列<space><tab>以及<newline>在开始和以前扩张的结果最终会被忽略,而不是在开始或结束的IFS字符的任何序列用于划字。如果 IFS 的值不是默认值,则在单词的开头和结尾处忽略空格字符 space、tab 和换行符的序列,只要空格字符在 IFS 的值中(一个 IFS 空格字符)。 IFS 中非 IFS 空格的任何字符,以及任何相邻的 IFS 空格字符,都用于分隔字段。一系列 IFS 空白字符也被视为分隔符。 如果 IFS 的值为空,则不发生分词。[强调。]

示例:字段拆分

如果 IFS 没有空格字符,则字段中包含空格:

$ ( IFS=',' x='one , two,three'; printf "<%s>\n" $x )
<one >
< two>
<three>
Run Code Online (Sandbox Code Playgroud)

如果 IFS 既有空格又有逗号,则空格序列,后跟逗号,后跟空格序列被视为单个分隔符:

$ ( IFS=' ,' x='one , two,three'; printf "<%s>\n" $x )
<one>
<two>
<three>
Run Code Online (Sandbox Code Playgroud)

逗号序列被解释为空字段序列:

$ ( IFS=' ,' x='one,,,two,three'; printf "<%s>\n" $x )
<one>
<>
<>
<two>
<three>
Run Code Online (Sandbox Code Playgroud)

示例:前导和尾随空格

如果 IFS 不包含空格,则任何前导和尾随空格都保留在字段中:

$ ( IFS=',' x='  one , two,three  ,'; printf "<%s>\n" $x )
<  one >
< two>
<three  >
Run Code Online (Sandbox Code Playgroud)

如果 IFS 确实包含空格,则删除任何前导或尾随空格序列:

$ ( IFS=' ,' x='  one , two,three  ,'; printf "<%s>\n" $x )
<one>
<two>
<three>
Run Code Online (Sandbox Code Playgroud)