嵌套引用的噩梦:从远程主机发送电子邮件

Ewa*_*noy 3 ssh email quoting

我需要(从我的终端)发送一封电子邮件,其中包含来自我通过 ssh 访问的远程主机的附件。我已经知道要远程执行某些操作,我使用

ssh -p myport myusername@myhost.com "doSomething"

我也知道要发送带附件的电子邮件,我会

echo "Mail content" | mailx -s "Mail title" -a attachment.txt -S from="myname@gmail" destname@gmail

因此,两者的天真组合将简单地用doSomething第二行的所有内容替换第一行。这当然不起作用,因为可怕的嵌套双引号。如何使这项工作(如果可能的话,干净利落)?任何帮助表示赞赏。

der*_*ert 7

对于简单的情况,您可以使用单引号来保护您的命令不受本地 shell 的影响,或者将双引号转义为\".

echo "Mail content" | ssh -p myport myusername@myhost.com 'mailx -s "Mail title" -a attachment.txt -S from="myname@gmail" destname@gmail'
# or
echo "Mail content" | ssh -p myport myusername@myhost.com "mailx -s \"Mail title\" -a attachment.txt -S from=\"myname@gmail\" destname@gmail"
Run Code Online (Sandbox Code Playgroud)

对于更复杂的事情,最简单的方法可能是使用 heredoc 来设置变量:

read -r -d '' mailcmd <<'CMD'
echo "quotin'" 'this would be a "nightmare" indeed.' | mailx -s "Anthony's Email" -a attachment.txt -S from="myname@gmail" destname@gmail
CMD
ssh -p myport myusername@myhost.com "$mailcmd"
Run Code Online (Sandbox Code Playgroud)

至少在 bash 中,您可以要求 shell 为您引用一个变量,这在您需要做更烦人的事情时可能会有所帮助(例如,链接两个ssh调用):

echo "Mail content" | ssh -p myport myusername@myhost.com 'mailx -s "Mail title" -a attachment.txt -S from="myname@gmail" destname@gmail'
# or
echo "Mail content" | ssh -p myport myusername@myhost.com "mailx -s \"Mail title\" -a attachment.txt -S from=\"myname@gmail\" destname@gmail"
Run Code Online (Sandbox Code Playgroud)

如您所见,它的自动引用并未针对最少的反斜杠进行优化。

包括局部变量

如果需要在命令中使用变量,ssh 提供了一种特殊的工作方式:ssh 可以传递由SendEnv选项(客户端)和AcceptEnv选项(服务器)指定的环境变量。如果您传递环境变量,远程端 shell 可以像往常一样扩展它们(如果您在 here-doc 中有“$varname”,也会如此)。

除此之外,最简单的方法是省略 heredoc 上的引号,这将使扩展发生(尽管这意味着您必须$在不想要的地方转义):

$ var1="hello world"
$ read -r -d '' mailcmd <<CMD
echo "$var1" "\$var1"
CMD
$ echo "$mailcmd"
echo "hello world" "$var1"
Run Code Online (Sandbox Code Playgroud)

注意我是如何使用CMD而不是'CMD'; 像这样引用结束标记会关闭扩展。因此,通过不引用它,我们得到了扩展。而"$var1"被扩大到hello world符合市场预期,但通过把一个反斜杠在它的前面可避免扩张。请注意,所有扩展都已启用,包括反引号和$(…)扩展。另请注意, var1 只是被替换;shell 没有在那里做任何转义,所以如果 var1 包含双引号(等),那将不起作用。这是您可以使用 %q 的一个地方:

$ var1='hello "world"'
$ read -r -d '' mailcmd <<CMD
echo $(printf '%q' "$var1") "\$var1"
CMD
$ echo "$mailcmd"
echo hello\ \"world\" "$var1"
Run Code Online (Sandbox Code Playgroud)

警告:如果您传递的数据可能会受到攻击者的影响,您必须非常小心。转义过程中的任何轻微错误(或在所有涉及的外壳之间需要转义的内容的不同定义)都可能成为任意代码执行缺陷。构建更强大的数据传递系统通常比确保所有必需的转义都存在/正确更容易。一个很大的安全漏洞已经逃脱失败。