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


18

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

IFS=" "
x="hello   hi   world"
./myprogram $x
argv[1] = hello
argv[2] = hi
argv[3] = world

但是,当我将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

这是为什么?


仅供参考,“ IFS”表示内部场分隔符
pr1268

Answers:


21

记录在中man bash。IFS中出现的任何非空格字符都将分隔一个字段。

来自man bash

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

示例:字段拆分

如果IFS没有空格字符,则这些字段中包括空格:

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

如果IFS同时包含空格和逗号,则将空格序列,逗号,空格序列视为单个定界符:

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

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

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

示例:前导空格和尾随空格

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

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

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

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

也许还值得强调“然后,只要该空白字符位于IFS的值内,则该单词的开头和结尾都将忽略空白字符,空格和换行符的序列”
Jeff Schaller

@JeffSchaller很棒的主意:我刚刚添加了一个部分。
John1024 '17


如果您使用制表符分隔的文件缺少一些值怎么办?也就是说,您不希望将标签序列视为单个标签。另外,这些字段包含逗号,因此不能将其用作分隔符。是使用其他定界符(而非制表符)的唯一解决方案吗?
达沃斯

@Davos对于每个字段都由单个制表符分隔的数据,使用其他轻松处理此问题的工具(例如awk带有-F'\t'或的选项)可能更自然cut。或者,如果您使用的最新版本bash,则可以使用readarray带有-d$'\t'选项的字段进行解析。
John1024 '18
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.