此代码在 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
最佳答案
2
这个特定的 bash 错误在 4.0 中得到了修复,该版本发布于 15 年前,但 macos 仍然发布 3.2.x 版本。由于 Apple 显然不会升级他们的版本bash
(sh
据我所知,他们的版本仍然基于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 将简化引用地狱。他们并没有表明他们同时拥有两者……
–
|
bash --version
每种情况是什么? (2) 这里的“可移植”是什么意思?你的意思是“遵循 POSIX”还是“即使存在新版本中已修复的错误也能正常工作”?这里可能有一个相关的–
–
|