1

我一直在尝试通过使用此处的文档将它们嵌套在更大的脚本中来简化一组脚本的安装(因此我仍然可以像普通脚本一样编辑它们)。然而,虽然这里文档中的任何内容都不应该被解释,但我的 shell 似乎偶然发现了不匹配的右括号,例如可以在 case 语句中找到。

例如:

#!/bin/sh
script=$(cat <<- 'NESTED_SCRIPT'
    case "$1" in
        foo)
            echo "Foo"
        ;;
        bar)
            echo "Bar"
        ;;
    esac
NESTED_SCRIPT
)

case除非在语句中的右括号之前放置反斜杠,否则上述操作将在第 6 行失败并出现语法错误。就像由于某种原因,shell 没有等待特殊的 here 文档终止,而是在找到第一个没有相应左括号的右括号后立即终止。不幸的是,转义括号不是一种选择,因为这给我留下了一个脚本,需要从其中删除反斜杠;虽然我可以这样做,但我想如果可以的话,我宁愿避免它。

无论如何,我知道这是一个奇怪的用例,但我不明白为什么它会像这样提前终止。有没有一种方法可以强制它仅以NESTED_SCRIPT序列终止而不解释括号,或者我可以使用其他一些解决方法?不幸的是,由于我使用它的方式(使用eval),我需要将脚本分配给一个变量。

4

3 回答 3

3

POSIX 标准允许一个前导括号来平衡最后一个以防止输入,因此您可以通过这种方式修复您的脚本:

#!/bin/sh
script=$(cat <<- 'NESTED_SCRIPT'
    case "$1" in
        (foo)
            echo "Foo"
        ;;
        (bar)
            echo "Bar"
        ;;
    esac
NESTED_SCRIPT
)

这应该适用于所有现代 shell,如ksh,bash等。

于 2013-10-23T06:07:24.613 回答
3

OP 中的解决方案适用于 Linux,但不适用于 osx。

将 here 文档分配给变量的正确方法似乎是这样的:

read -r -d '' script <<- 'NESTED_SCRIPT'
... # your nested script...
NESTED_SCRIPT

但这仅适用于不太旧的版本bash,它不适用于没有标志/bin/sh的 Debian 。read-d

如果你想要更便携的东西,你可以试试这个更丑的解决方案:

script=
IFS=''
while read line; do
    script="$script$line\n"
done <<- 'NESTED_SCRIPT'
    case "$1" in
        foo)
            echo "Foo"
        ;;
        bar)
            echo "Bar"
        ;;
    esac
NESTED_SCRIPT

您可以在其他问题中找到更多详细信息和建议:

如何将heredoc值分配给Bash中的变量?

但...

如果您只想重复使用相同的脚本在本地和远程运行,那么有一种比eval在远程端使用更好的方法。您可以像这样在远程服务器上运行本地脚本:

ssh myserver bash < script.sh

如果要将命令行参数传递给脚本,可以这样做:

ssh myserver bash -s arg1 arg2 < script.sh
于 2013-10-19T21:35:26.870 回答
2

语法错误的原因是)脚本中的第一个关闭了进程替换。通常,我会争辩避免像瘟疫这样的反引号并使用$()语法。但在这种情况下...

#!/bin/sh
script=`cat <<- 'NESTED_SCRIPT'
    case "$1" in
        foo)
            echo "Foo"
        ;;
        bar)
            echo "Bar"
        ;;
    esac
NESTED_SCRIPT
`

只要确保避免在任何嵌入式脚本中使用反引号,就可以了。

于 2013-10-23T06:00:47.950 回答