在heredocs的输入中使用单引号

在heredocs的输入中使用单引号

我需要一些帮助来调试我的 tcsh 脚本。它使用heredocs。代码:

<pre_setup> <<EOF1
<setup> <<EOF2

<command>

exit 0
EOF2
exit 0
EOF1

<pre_setup>是一些预设置命令(例如wash),并且setup是在它之后运行的一些设置。它有效,但我注意到如果setup包含单引号,它会失败。我的设置如下:

run_setup -cmd '$SOME_ENV -o outdir'

设置run_setup$SOME_ENV执行$SOME_ENV -o outdir.所以运行:

wash -n group_name <<EOF1
run_setup -cmd '$SOME_ENV -o outdir' <<EOF2

<command>

exit 0
EOF2
exit 0
EOF1

失败SOME_ENV: Undefined variable.。这不是washin的问题pre_setup,因为如果我使用setenv X 1(或cat) as pre_setup,它仍然会失败并出现相同的错误。它与heredocs 的工作方式有关。我怎样才能让它发挥作用?难道是逃跑的问题?如何调试这里文档?

我还要提到的是,run_setup -cmd '$SOME_ENV -o outdir'在 shell 中运行是有效的。甚至跑步pre_setup,然后这就setup可以了。所以这与heredocs有关。

编辑:用引号括起来,像这样打破代码:

/bin/tcsh <<EOF
$WORK_AREA/script.sh.$1
echo \$status > $WORK_AREA/.$1.result
exit 0
EOF

其中 $1$ 是具有 this 的脚本的输入heredocs。当用单引号括起来时,$1in$WORK_AREA/script.sh.$1为空。但如果没有引号,它就可以工作。为什么?我该如何解决?

答案1

常规的here-doc有点像双引号字符串,因为它扩展变量等:

foo=there
cat <<EOF
hello $foo
EOF

输出“你好”。在 sh-likes 中,如果未定义变量,通常不会出现错误,您只会得到一个空字符串。

请注意,引号不相关。它们在此处文档中并不特殊,就像单引号在双引号中并不特殊一样。例如,这也扩展了$fooecho "hello '$foo'"

看来您想阻止扩展,您可以通过引用分隔符来做到这一点。不过,类似 sh 的 shell 和 (t)csh 之间似乎有些区别。

在 sh-likes 中,这个:

foo=there
cat <<'EOF'
hello $foo
EOF

prints hello $foo,即不尝试扩展变量。

在 (t)csh 中,您似乎需要以相同的方式引用结束分隔符,因此:

foo=there
cat <<'EOF'
hello $foo
'EOF'

Debian 中的 tcsh 手册页说:

<< word
读取 shell 输入直到与以下内容相同的行单词单词不受变量、文件名或命令替换的影响,并且每个输入行都与单词在此输入行上进行任何替换之前。

除非引用\, ",'`出现在单词[, ] 变量和命令替换在中间行上执行,允许\引用$,\`

我认为“最多一行相同”(和“替换前比较”)意味着引用相同。 (这与 Bash 手册页的描述不同:“如果单词被引用,分隔符是删除引号的结果单词,[...]”。)

第二部分与 POSIX sh 中的相同,带引号的分隔符会抑制此处文档文本中的扩展。


如果您从此处文档提供 shell,则您将拥有两个可以扩展任何变量的 shell。构建here-doc的外壳,然后运行内部外壳来读取它。他们可能对变量是什么有不同的想法,例如内部变量不会有主脚本的参数。引用和转义决定了其中哪一个扩展变量。

所以如果你运行这个:

#!/usr/bin/tcsh
set foo = outer
echo in outer shell, foo is: $foo

tcsh <<EOF
set foo = inner
echo "not escaped, outer shell expands: $foo"
echo "    escaped: inner shell expands: \$foo"
EOF

内壳看到

set foo = inner
echo "not escaped, outer shell expands: outer"
echo "    escaped: inner shell expands: $foo"

第一个$foo已经展开,并且反斜杠从\$foo.如果你用它<<'EOF'代替,外壳不会膨胀。

因此,在这里,您需要使用<<EOF不带引号的内容,并根据您想要发生的情况,注意单独转义或不转义所有变量。

相关内容