当设置 IFS 在换行符上拆分时,为什么需要包括一个后退空间?

我很好奇为什么在像下面这样将 IFS 设置为换行时需要后退空间:

IFS=$(echo -en "\n\b")

为什么我不能直接使用这个(它不工作)呢?

IFS=$(echo -en "\n")

我在一个 Linux 系统上,它以 Unix 行结尾保存文件。我用换行符将文件转换为十六进制,它肯定只使用“0a”作为换行符。

我谷歌了很多,虽然许多网页文件换行后面的退格解决方案,我没有找到任何解释为什么退格是必需的。

大卫。

108233 次浏览

因为正如 bash 手册所说,关于 指令替代:

Bash 通过执行 command 并用命令的标准输出替换指令替代来执行扩展,并删除所有尾随的换行符。

因此,通过添加 \b可以防止去除 \n

更简单的方法是使用 $''引用,如下所示:

IFS=$'\n'

这是一个黑客行为,因为使用了 ABc0和指令替代。

prompt> x=$(echo -en "\n")
prompt> echo ${#x}
0
prompt> x=$(echo -en "\n\b")
prompt> echo ${#x}
2

$()条带尾随换行符和 \b防止 \n作为一个尾随换行符,同时极不可能出现在任何文本中。IFS=$'\n'是将 IFS 设置为换行分割的更好方法。

我只记得最简单的方法。 在 Debian Wheezy 上测试了 bash。

IFS="
"

别开玩笑了:)

只要按回车键而不指定任何内容也可以工作。虽然,它看起来像有人犯了一个错误,难以理解。

IFS=
#This is a line

作为新行 \n后缀的 \b字符是由于去除了指令替代 $(...)中的尾巴 \n而添加的。因此,\b被用作 \n的后缀,这样 \n就不再是后缀,所以从指令替代返回。

副作用是,IFS也将包括 \b字符作为一个分隔符,而不仅仅是 \n,这真的是我们唯一的兴趣。

如果您预期 \b有一天会出现在字符串中(为什么不呢?) ,那么您可以使用:

IFS="$(printf '\nx')" && IFS="${IFS%x}";

那个 returns \n suffixed with x && removes x

现在 IFS 只包含 \n字符。

IFS="$(printf '\nx')" && IFS="${IFS%x}";
echo ${#IFS}; # 1

\b的情况下,没有东西会破裂,测试:

#!/bin/sh


sentence=$(printf "Foo\nBar\tBaz Maz\bTaz");
IFS="$(printf '\nx')" && IFS="${IFS%x}";


for entry in $sentence
do
printf "Entry: ${entry}.\n";
done

给出两行(由于一个 \n) :

Entry: Foo.
Entry: Bar      Baz Maz Taz.

不出所料。

IFS="$(printf '\nx')" && IFS="${IFS%x}";使用:

IFS="
"

给出相同的结果,但这两行不能缩进,如果你不小心把空格或制表符或任何其他白字符之间的“和”,你将不再只有 \n字符,但一些“奖金”。 除非在编辑器中使用“显示所有字符”选项,否则很难发现这个 bug。