【问题标题】:Capture output of double-ssh (ssh twice) session as BASH variable将双 ssh(ssh 两次)会话的输出捕获为 BASH 变量
【发布时间】:2016-10-28 04:24:41
【问题描述】:

我想捕获 ssh 会话的输出。但是,我首先需要 ssh 两次(从我的本地计算机到远程门户到远程服务器),然后运行命令并捕获输出。

逐行执行,我会这样做:

ssh name@remote.portal.com
ssh remote.server.com
remote.command.sh

我尝试了以下方法:

server=remote.server.com  ##define in the script, since it varies
sshoutput=$(ssh -tt name@remote.portal.com exec "ssh -tt ${server} echo \"test\"")
echo $sshoutput

我希望上面的脚本在最终命令之后回显“test”。但是,在我输入命令后,外部 ssh 提示符只是挂起,一旦我 Ctrl+c 或无法输入我的密码,内部 ssh 会话就会失败(我相信因为 stdout 不再打印到屏幕上,我不再得到我的密码提示)。

如果我只运行内部命令(即,没有“sshoutput=$(”将其保存为变量),那么它可以工作,但(显然)不捕获输出。我也尝试过没有“exec”。

我也尝试过将内部 ssh 保存为变量,例如

sshoutput=$(ssh -tt name@portal myvar=$(ssh -tt ${server} echo \"test\"") && echo $myvar)

但这失败了,因为 BASH 在将内部 ssh 发送到外部 ssh 会话之前尝试执行内部 ssh(我相信),并且无法识别服务器名称。

(我看过https://unix.stackexchange.com/questions/89428/ssh-twice-in-bash-alias-function,但他们只是说“如果使用交互式密码需要更多标志”并且没有解决捕获输出的问题)

提前感谢您的帮助!

【问题讨论】:

  • 到目前为止,最好的方法是使用ProxyCommand 让 ssh 自己完成设置内部 ssh 会话的工作。
  • 你为什么使用-tt?我不确定这对这个问题有什么影响,但似乎没有必要。
  • @ProxyCommand 评论:类似于下面的链接?我上面的 remote.command.sh 实际上设置了一个 VNC 服务器并返回要使用的端口(例如,“:3”),然后我 ssh 隧道到该端口。以下链接中的命令会干扰(和/或没有权限)吗? cyberciti.biz/faq/…
  • @cwotta,请在在您的问题本身中包含足够的内容来生成和测试答案,而不是在链接后面(特别是在cyberciti.biz链接后面;我不会不要用 10 英尺长的杆子碰它)。也就是说,一般来说,ProxyCommand 的使用不会干扰其他类型的 SSH 代理支持。
  • @why -tt:通过查看各种网站,似乎有必要,因为我是双重 ssh-ing。我会收到“不是真正的终端”类型的错误(具体记不清了),但它似乎不再是问题,因为我只是在没有它的情况下进行了测试,但它不再存在,尽管我的命令无法执行。跨度>

标签: bash ssh


【解决方案1】:

这里的最佳实践方法是让 ssh 自己完成跳过您的弹跳主机的工作。

result=$(ssh \
  -o 'ProxyCommand=ssh name@remote.portal.com nc -w 120 %h %p' \
  name@remote.server.com \
  "remote.command.sh")

您可以在 ~/.ssh/config 中自动执行该操作,如下所示:

Host remote.server.com
    ProxyCommand ssh name@remote.portal.com nc -w 120 %h %p

...之后任何ssh remote.server.com 命令将自动跳转到remote.portal.com。 (将nc 更改为netcat 或类似名称,适用于安装在bouncehost 上的工具)。


也就是说,如果你真的想自己动手,你可以:

printf -v inner_cmd '%q ' "remote.command.sh"
printf -v outer_cmd '%q ' ssh name@remote.server.com "$inner_cmd"
ssh name@remote.portal.com bash -s <<EOF
$outer_cmd
EOF

...最后一部分可以像这样在命令替换中运行:

result=$(ssh name@remote.portal.com bash -s <<EOF
$outer_cmd
EOF
)

【讨论】:

  • 如果您总是需要使用代理来访问该远程服务器,您可以将其放入您的.ssh/config
  • @CharlesDuffy -- 更新:我错了。我正在使用第一个代码块。它不会将输出捕获到 $result 中,它只是将其打印到屏幕(stdout)——我最初认为它有效,因为我在之后回显 $result 以检查——否则,它有效(即,我能够登录并执行命令)。此外,我尝试了最后两个代码块并立即收到三个“权限被拒绝”错误。这并不重要,因为我没有使用这种方法,但我想我会注意它。
  • 您确定您使用的是第一个代码块已编辑吗?第一个版本根本没有捕捉到(留给读者的是一个——相当明显的——练习)。
  • ...如果它仍然没有捕获,那么您尝试抓取的内容很有可能实际上是进入标准错误,而不是标准输出。在命令替换的结束括号之前放置一个2&gt;&amp;1
  • ...对于权限被拒绝错误,使用set -x 记录在本地运行的确切命令,并将bash -s 更改为bash -x -s 以对远程位执行同样的操作。并发布输出。如果您在需要将 "remote.command.sh" 'argument 1' 'argument 2' 传递给 printf 或类似的时将 "remote.command.sh 'argument 1' 'argument 2'" 传递给我,我不会感到惊讶;给出日志时应该很明显。
猜你喜欢
  • 2012-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 2020-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多