如何*不*在 tcsh backtick/eval 包装器中扩展“~”?

How to *not* expand "~" in tcsh backtick/eval wrapper?

我对 "why tcsh is evil" 的回答不感兴趣,这个问题需要 tcsh 才能使用。如果这是 tcsh 中的错误,请告诉我。

我通常很擅长引用输出,但我一直被我必须处理的用例难住了。这是简化的案例:

我有一个可执行文件,我对其输出进行评估。有时它需要打印输出(到标准输出)所以我尝试使用回声(内置),/bin/echo 和 /bin/printf.

举个简单的例子,假设我的可执行文件名为 "simpleWrap" 并且它 输出 :

echo "hello world"

所以我运行(最终使用别名,但这与这里无关):

eval `simpleWrap`

我得到了,如预期的那样:

hello world

但这就是问题所在。有时我需要在输出中使用波浪号。因此,让我们尝试一些示例。我们将波浪号放在 simpleWrap 输出中(这不是脚本的内容,而是它 输出 的内容):

echo "These are tildes:  ~ and \~ and \~"

令人惊讶的是,当我现在评估 simpleWrap 的输出时,我得到:

These are tildes: /home/dave and \~ and \~

要么~扩展到我的主目录,要么\保护它,但我无法摆脱反斜杠。

如何在带有反引号的 eval 输出中打印一个“~”?

我相信反引号会迫使 ~ 扩展,但它们并没有以一致的方式进行。例如,如果我跳过反引号并执行:

eval echo "These are tildes:  ~ and \~ and \~"

然后我得到一致的预期输出:

These are tildes: /home/dave and ~ and \~

反引号替换有问题,还是我错过了正确的引用可能性? (我也试过用单引号和双引号引起来都无济于事)

不同之处在于 顺序 shell 替换发生 ,以及当 \ 在双引号内时解析 \ 的不同行为,而不是没有双引号。

演示 \ 的行为:

echo \~
=> ~
echo "\~"
=> \~
echo "\~"
=> \~

场景一

eval `simpleWrap`

这里,“simpleWrap”输出一个包含波浪号的 "raw" 字符串。然后将字符串原样(无替换)传递给 eval 命令(因为这就是反引号的工作方式),基本上 运行 是一个新的 shell。所以新的 shell 看到这个命令行:

echo "These are tildes:  ~ and \~ and \~"

(请注意,引号是通过 eval 命令看到的)。

此命令的输出是您没有预料到的,即 \~(表示 A)和 \~(表示 B)产生相同的输出。为什么?

首先,A 和 B 都没有被替换,因为只有当波浪号是其单词中的第一个字符时才会发生波浪号替换,而这两者都不是这种情况。

现在,对于 A,由于 \~ 不是已知的转义序列(例如与 \n 不同),shell 保持原样,生成 \~ .

对于B,\ 一个已知的转义序列,因此shell正确地将其解释为\,然后附加其余部分的字符串,再次生成 \~

场景 2

eval echo "These are tildes:  ~ and \~ and \~"

在这里,只有一个命令行,其中包括波浪号。首先,有 shell 替换,它既不影响 A 也不影响 B,但在这个阶段,引号会下降(它们用于将单词分组为单个参数,并且不会传递给命令)。然后,eval 运行s(echo 还没有 运行),并将其作为输入传递:echo These are tildes: ~ and \~ and \~.

请注意删除的引号。不带引号的命令输出是您所期望的(参见上面的 "demonstration"):

echo These are tildes:  /home/dave and \~ and \~
=> These are tildes: /home/dave and ~ and \~

如何让它发挥作用?

去掉引号!

simpleWrap 应该打印这个:

echo These are tildes:  ~ and \~ and \~

而不是这个:

echo "These are tildes:  ~ and \~ and \~"