将IFS设置为在换行符上分割时,为什么需要包含退格键?


70

我很好奇为什么将IFS设置为在换行符上拆分时为什么需要退格键:

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

为什么我不能只使用它(不起作用)呢?

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

我在使用Unix行尾保存文件的Linux系统上。我已经用换行符将文件转换为十六进制,并且肯定只使用“ 0a”作为换行符。

我已经在Google上搜索了很多,尽管有很多页面记录了换行符和后退解决方案,但是我发现却没有一个解释为什么需要退格。

-大卫。


有人可以说他们在哪里看到这样的代码吗?谢谢。
spbnick '16

@spbnick每当您要遍历文件时(例如,在中),都需要重置IFS for file in $(ls) ; do echo "$f" ; done。如果不将IFS设置为仅换行符,则for循环将单独回显每个文件名中每个以空格分隔的块,而不是整个文件名。
bleistift2

感谢@ bleistift2,我了解为什么有人想要更改IFS,并且我了解代码的工作原理(我的回答在这里是最受欢迎的)。我只是很好奇IFS中退格字符的这种特殊用途来自何处,以及历史上是谁提出的。因此,我要问人们在哪里看到了这种代码。
spbnick

Answers:


128

因为如bash手册所述,关于命令替换

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

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

一种更干净的方法是使用$''引号,如下所示:

IFS=$'\n'


1
虽然应该在某个时候将它们包含在Posix中,但它们目前尚不存在,并且在许多与posix shell链接而不是bash链接的地方,/ bin / sh不能使用。
约翰·艾肯伯里

1
但是当我想使用换行和读取命令拆分数组时。仅将第一项添加到hostArray。但是主机有4个项目。host=$(mysql -S $socket $catalog --skip-column-names -e "select host from mysql.user); echo "Host: $host"; IFS=$'\n';read -ra hostArray <<< "$host"; echo "HostArray:$hostArray" #This prints only 1 item. But there are 4 items;怎么了
古纳


12

由于使用了echo和命令替换,因此很hack 。

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

所述$()条带后新行和\b防止\n从被,同时非常不可能出现在任何文本尾随换行符。IFS=$'\n'是将IFS设置为在换行符上分割的更好方法。


2
这表明该\n\b构造还包括退格IFS符作为分隔符,因此在某些情况下我会认为它已损坏。
汤姆·黑尔

3

\b\n由于删除\n了命令替换$(...)的尾部,因此添加了char作为换行符的后缀,因此将\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字符,而是拥有一些“奖励”,那将很难点,除非您使用选项在编辑器中显示所有字符。


1

仅按Enter键而不分配任何内容也可以。虽然,看起来有人犯了一个错误并且很难理解。

IFS=
#This is a line

1
这不是将$ IFS设置为空字符串吗?
Marius Gedminas

好吧,您在'='符号后按Enter即可使其正常工作。当我尝试时它起作用了。@moddie的答案看起来更加清晰。
taiyebur
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.