关闭这里文件的括号

时间:2013-10-19 13:46:47

标签: shell

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

例如:

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

除非在case语句中的右括号之前放置反斜杠,否则上面的代码将失败,第6行会出现语法错误。由于某种原因,shell不等待特殊的文档终止,但是一旦找到没有相应开口括号的第一个右括号就会终止。不幸的是,转义括号不是一个选项,因为这给我留下了一个需要从中删除反斜杠的脚本;虽然我能做到这一点,但我想如果可以的话我宁愿避开它。

无论如何,我知道这是一个奇怪的用例,但我无法理解的是为什么它会像这样早点终止。有没有办法可以强制它只用NESTED_SCRIPT序列终止而不解释括号,或者我可以使用的其他一些解决方法?不幸的是,我需要将脚本分配给变量,因为我正在使用它(使用eval)。

3 个答案:

答案 0 :(得分:3)

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

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

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

但这仅适用于不太旧的bash,但在/bin/sh没有read标记的Debian -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

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

How to assign a heredoc value to a variable in Bash?

<强> BUT ...

如果您只想重复使用相同的脚本在本地和远程运行,那么比在远程端使用eval要好得多。您可以在远程服务器上运行本地脚本,如下所示:

ssh myserver bash < script.sh

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

ssh myserver bash -s arg1 arg2 < script.sh

答案 1 :(得分:3)

POSIX标准允许前导括号在大小写条目中平衡最后一个,所以你可以这样修复你的脚本:

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

这适用于所有现代shell,例如kshbash等。

答案 2 :(得分:2)

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

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

请确保您避免在任何嵌入式脚本中使用反引号,并且您应该没问题。