此代码在 Linux 上运行良好,但在 Mac OS 上运行不佳:

#!/usr/bin/env bash
foo=$(cat <<EOF
"\[^"\]+"
EOF
)
printf "%s" "$foo"

在 Mac 上失败

./test.sh: line 6: unexpected EOF while looking for matching `"'
./test.sh: line 7: syntax error: unexpected end of file

如果我这样做cat <<EOF而不是foo=$(cat <<EOF,它工作得很好。有没有一种可移植的方法可以将 heredocs (或多行字符串) 放入变量中,而无需使用文件作为中间体?

2

  • 1
    (1)bash --version每种情况是什么? (2) 这里的“可移植”是什么意思?你的意思是“遵循 POSIX”还是“即使存在新版本中已修复的错误也能正常工作”?这里可能有一个相关的


    – 

  • @KamilMaciorowski,这不可能是那个修复,因为这个错误已经在 4.0 中修复了。


    – 


最佳答案
2

这个特定的 bash 错误在 4.0 中得到了修复,该版本发布于 15 年前,但 macos 仍然发布 3.2.x 版本。由于 Apple 显然不会升级他们的版本bashsh据我所知,他们的版本仍然基于bash),我建议您向他们报告这个错误,以便他们将修复程序移植到他们的版本中。

它似乎会影响命令替换中使用的 here-documents,因此您可以使用以下命令将 here-doc 移出命令替换:

#!/usr/bin/env bash
{
  foo=$(cat)
} <<'EOF'
"\[^"\]+"
EOF
printf %s "$foo"

或者使用辅助函数:

#!/usr/bin/env bash
helper() {
  cat <<'EOF'
"\[^"\]+"
EOF
}
foo=$(helper)
printf %s "$foo"

(上面也使用'EOF'而不是EOF因为后者进行扩展并意味着对反斜杠的额外处理)。

或者通过使用以下方式延迟此处文档的解释eval

#!/usr/bin/env bash
foo=$(eval 'cat <<EOF
"\[^"\]+"
EOF')
printf %s "$foo"

虽然我怀疑您首先使用此处的文档是为了避免担心引用嵌套,但这eval '...'可能无济于事。

术语说明:

  • Mac 是 Apple 生产的一系列不同架构的计算机硬件(其中一些基于 PC),可以运行各种类 Unix 或非类 Unix 操作系统,但预装了 Apple macos(以前称为 OS/X、MacOS/X)。因此几乎不相关。
  • Unix 是一个操作系统家族,其历史可以追溯到 70 年代贝尔实验室开发的原始 Unix 操作系统,macos 和大多数通用的基于 GNU/Linux 的操作系统都属于该操作系统。
  • Linux 是数千种不同操作系统的核心,其中一些(大多数)类似于 Unix,有些则不是。
  • bash 是 GNU 项目的 shell,它基本上是 Korn shell(直到 2000 年左右才开放源代码)的免费开源部分克隆,于 1989 年首次发布(因此早于 Linux 和 MacOS/X),可以为大多数(如果不是全部)类 Unix 系统和几个非类 Unix 系统构建。它预装在 GNU 系统、几个非 GNU 基于 Linux 的系统和一些非 GNU 非 Linux 系统(如 macos)上,尽管在那里,它是一个非常古老的 GPL3 之前的版本。

这里,问题仅仅与 bash 的版本有关,您会在 2009 年之前的任何包含 bash 的系统中遇到同样的错误。

2

  • @StephenKitt,上次我靠近 Mac 时,它们能够运行 Microsoft Windows(当时是 XP 或 7)。support.apple.com/en-us/102622你仍然可以(至少在某些型号上)。


    – 


  • 另一个可能的助手可能是set_x() { x=$(cat) }。现在set_x<<EOF可以工作了,如果使用多个HEREDOC,它将很有用。


    – 

我不清楚为什么需要 heredoc:

foo='"\[^"\]+"'

应该在 Linux 和 macOS 上的 bash 中运行。

如果需要多行字符串,请在多行中用引号声明它:

foo='a
multi-line
string'

1

  • 1
    如果 (如果) 他们的字符串同时包含单引号和双引号,则 heredoc 将简化引用地狱。他们并没有表明他们同时拥有两者……


    –