【问题标题】:read <<<$(myfunc) behavior differs between bash 4.2 and 4.4bash 4.2 和 4.4 之间的读取 <<<$(myfunc) 行为不同
【发布时间】:2017-09-10 16:34:46
【问题描述】:

下面有一些代码可以从列表中读取数组

#!/usr/local/bin/bash

function getlist {
    printf "%q/\n" "foo"
    printf "%q/\n" "bar"
}

IFS="$(printf ' \n\t')"
# IFS=" "

while read -r tmp; do
    echo "test"
    echo $tmp
done <<< $(getlist)

4.2 bash 输出

$ ./test.sh
test
foo/ bar/

4.4 输出

$ ./test.sh
test
foo/
test
bar/

但是,如果我更改 IFS=" ",它们的行为与 4.4 相同(但实际上分隔符是 \n,对吗?)。想知道这两个版本之间有什么变化

【问题讨论】:

  • 顺便说一句,最好使用符合POSIX的getlist() {声明语法,前面没有functionfunction 就像 let 一样,是一种向后兼容的痕迹(在这种情况下是用于 ksh),与兼容(因此可移植)的替代品相比没有任何优势。
  • 另外,IFS=$' \n\t' 比使用printf 运行命令替换要高效得多。 (在 ksh93 中,shell 实际上并没有 fork 进行替换,只是在当前 shell 中运行 printf ——但 bash 没有这种优化)。

标签: bash


【解决方案1】:

问题不在于read,而在于您没有引用此处的字符串。如果你引用它,你在两种情况下都会得到 4.4 的结果:

#!/usr/local/bin/bash

function getlist {
    printf "%q/\n" "foo"
    printf "%q/\n" "bar"
}

IFS="$(printf ' \n\t')"
# IFS=" "

while read -r tmp; do
    echo "test"
    echo $tmp
done <<< "$(getlist)"

在 bash 4.4 中有所不同,因为它修正了与文档的偏差,如在以下位置找到的 in the release notes

z。 Bash 不再像文档中所说的那样拆分 here-strings 的扩展。

【讨论】:

  • 添加报价确实使它们相同。但仍然对几件事感到好奇。 (1) 为什么报价很重要? (2) 4.4 不需要引号怎么办 (3) 为什么把 IFS 改成 "" 行得通
  • @fushupinnanren,(1) 双引号抑制字符串拆分和全局扩展。这是他们在 shell 中的主要目的——毕竟没有特定于 read 或 heredocs 的内容。 (2) 正如文档所说,4.4 已经抑制了对 herestrings 的字符串拆分,所以如果它被抑制,即使没有引号也会被抑制。 (3) IFS 值不包含字符串中存在的任何字符意味着您的字符串不会被拆分。
  • @fushupinnanren 问题是 bash 正在对 here-string 应用分词,因此字符串中的任何 IFS 字符都将被删除并基本上替换为空格,然后 read 将看到那个结果。引号防止分词,在 bash 4.4 中他们修复了它,因此在这种情况下不会再发生分词
  • 谢谢。但是为什么拆分会使“读取”读取整个此处的字符串?这不是相反吗?如果这是一个幼稚的问题,请耐心等待。
  • @fushupinnanren 比较 bash v4.2 和 4.4 下 cat &lt;&lt;&lt; $(getlist) 的输出,以更清楚地了解发生了什么。另请参阅my answer to a similar question
猜你喜欢
  • 1970-01-01
  • 2019-12-04
  • 1970-01-01
  • 2017-05-08
  • 1970-01-01
  • 2012-11-04
  • 2014-11-01
  • 1970-01-01
  • 2018-05-07
相关资源
最近更新 更多