ssh - 执行复杂的远程命令

ssh - 执行复杂的远程命令

我想执行以下操作命令在一个偏僻的机器:

/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out

该命令使用一个名为 的二进制文件,它基本上是一个带有一些额外糖分的retail普通 Linux 。tail欲了解更多信息,您可以查看github 仓库。

当我在 shell 中输入上面的命令时在远程机器上它本身就是我想要的,所以从功能角度来看,所写的命令是正确的。它做我想要的。

问题是我想要执行脚本中的该命令在我的笔记本电脑上并触发远程机器。

这是什么我试过,但所有命令都不会打印所需的输出,而是不打印日志行完全:

ssh [email protected] /bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out

然后我尝试转义[]或使用'代替"和可能它的每一个组合,但一切没用

期望的输出是:表现得像平常一样tail,如果新行与字符串中的指定行匹配则退出。同样,当我在远程计算机上执行它时,它的工作原理如下。

我问自己:也许retail无法通过 ssh 运行?我已经尝试过普通的 Unixtail有用通过 ssh。作者retail说它符合 POSIX 标准人们可以tail用它替换他的系统。所以,我想这也是没问题二进制文件本身。

所以问题实际上是:如何格式化ssh命令的参数,以便它正确地获取命令?


对评论的回应杰肯551:

如果你的意思是:

ssh [email protected] '/bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out'

然后,是的,我已经尝试过了。它还打印没有日志行并且不返回到输入提示。


对 的回答的回应杰拉德·皮尔:

不幸的是同样的行为。不打印日志并且不返回输入提示。为了完整起见,我尝试了这个:

ssh [email protected] /bin/retail -f -u \'INFORMATION \\[main\\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \\[\\\"ajp-nio-8009\\\"\\]\' /opt/tomcat/logs/catalina.out

对 的回答的回应帕特里克:

不幸的是,也是负面的。为了完整起见,我尝试了两种建议的解决方案。这里的第一:

CMD="$(printf "%q " /bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
ssh [email protected] "$CMD"

结果:不打印日志并且不返回输入提示。

还有第二个:

ssh -T [email protected] <<'EOF'
/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF

结果:输出一个伪终端,但是不是日志并且确实不是返回到输入提示:

 Pseudo-terminal will not be allocated because stdin is not a terminal.
Linux my-remote-server 4.1.15-1-lts #1 SMP Tue Dec 15 20:54:13 CET 2015 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.

自从我尝试过现在有几个解决方案,我应该尝试一下调用 sh 脚本,其中包含retail命令为杰拉德·皮尔建议。我还想拥有漂亮的单行如果可能的话(无需编写包含该行的脚本)。


响应阿彻马尔回答:

我采用了原始命令,我指定了该命令并向-t其添加了 a,结果如下:

ssh -t [email protected] /bin/retail -f -u "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out

有效。 Archemar你应该写你的评论作为答案这样我就可以勾选它。

答案1

有时命令处理终端,因为这不是问题$PATH,您可能希望ssh分配一个tty.

按照man ssh

-t 强制伪终端分配。这可用于在远程计算机上执行任意基于屏幕的程序,这非常有用,例如在实现菜单服务时。多个 -t 选项强制 tty 分配,即使 ssh 没有本地 tty。

只需使用

ssh -t sshuser@host ...

答案2

Jaken551 的建议接近实际解决方案,但由于嵌套引用的额外级别而略有偏差。我们先来看看这到底是怎么回事。

echo我通常的技术是在命令前面加上一个(它并不完美,但通常足够好)。

# Your original command which you say works locally
$ echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

# The command though ssh
$ ssh example.com echo "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out
INFORMATION [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler [ajp-nio-8009] /opt/tomcat/logs/catalina.out

# The command through ssh with the quotes
$ ssh example.com 'echo "INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]" /opt/tomcat/logs/catalina.out'
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \["ajp-nio-8009"\] /opt/tomcat/logs/catalina.out

因此请注意输出的差异。在这两个ssh版本中,转义是不同的。

第一个示例中发生的情况ssh是,第一级引用被本地 shell 剥离,然后ssh接收多个参数 ( echo, INFORMATION \[main\] ...),然后将它们连接在一起形成一个参数echo INFORMATION \[main\] ...,然后通过本地 shell 上的 shell 对其进行求值远程端作为sh -c 'echo INFORMATION \[main\] ...'.

在第二个ssh示例中,第一级引用再次被本地 shell 删除,因此 ssh 接收echo "INFORMATION \[main\] ...",然后在远程端将其评估为sh -c 'echo "INFORMATION \[main\] ..."'。所以它好一点,但你仍然要处理 2 层 shell,剥离你的引号和转义符。

 

有两种方法可以解决这个问题。第一种方法是在 STDIN 上传递命令,这将确保您的命令仅在实际执行时由 shell 处理一次:

ssh -T example.com <<'EOF'
echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

然而,这意味着远程命令无法访问您的 TTY 或 STDIN,因此如果该命令需要 STDIN,它将无法工作。

第二种方法是让 shell 为您添加额外的报价级别。

$ CMD="$(printf "%q " echo 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
$ ssh example.com "$CMD"
INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out

(你不需要中介$CMD,你可以做一个内联ssh ... "$(printf "%q " ...)",我只是为了易读性而单独做了)

 

TL;DR:以下任一方法都适合您:

ssh -T [email protected] <<'EOF'
/bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out
EOF

CMD="$(printf "%q " /bin/retail -f -u 'INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]' /opt/tomcat/logs/catalina.out)"
ssh [email protected] "$CMD"

答案3

如果您只是在另一个系统上创建一个执行您想要的操作的脚本,然后在不带任何参数的情况下调用该脚本,那么您的工作会容易得多。另一种方法是在另一端创建一个脚本,显示它接收到的参数,例如 echo_args.sh:

#!/bin/ksh

echo "$0 $@"
ARG=1
while [ $# -gt 0 ]
do
  echo "$ARG: $1"
  shift
  (( ARG++ ))
done

然后你可以调用:

ssh [email protected] bin/echo_args.sh  -f -u \'INFORMATION \\[main\\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \\[\\\"ajp-nio-8009\\\"\\]\' /opt/tomcat/logs/catalina.out

你得到:

bin/echo_args.sh -f -u INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\] /opt/tomcat/logs/catalina.out
1: -f
2: -u
3: INFORMATION \[main\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \[\"ajp-nio-8009\"\]
4: /opt/tomcat/logs/catalina.out

这表明参数正确到达另一端。现在您只需将 echo_args.sh 替换为您的零售程序:

ssh [email protected] /bin/retail -f -u \'INFORMATION \\[main\\] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler \\[\\\"ajp-nio-8009\\\"\\]\' /opt/tomcat/logs/catalina.out

相关内容