简短的回答:$(ps ... )
命令替换正在本地计算机上运行,然后其输出(与echo
命令一起)发送到远程计算机。本质上,它正在运行ssh user@myserver.com echo 8630
。
您的第一个命令也可能没有按照您的预期执行;管道在本地计算机上进行解释,因此它正在运行ssh user@myserver.com ps -aux
,将输出管道传输grep
到本地计算机上,将其管道传输到本地计算机上的另一grep
台计算机等。我猜你希望整个事情在远程计算机上运行所以结果可以在远程计算机上用于终止进程。
长答案:在 shell 中解析和执行事物的顺序有点混乱;混合使用ssh
命令,事情变得更加复杂。基本上,发生的事情是本地 shell 解析命令行,包括将其拆分为单独的命令(由管道分隔;
,等),以及扩展$(command)
和$variable
替换(除非它们在单引号中)。然后它删除引号和转义符(他们已经完成了他们的工作)并将结果作为参数传递给各种命令(例如ssh
)。ssh
获取它的参数,将所有看起来像远程命令的一部分的参数与它们之间的空格粘在一起,然后将它们发送到远程计算机上的外壳,该外壳再次执行此过程。
这意味着如果您希望远程 shell 而不是本地 shell 对它们进行解析/操作,那么引用和/或转义诸如$
and之类的东西是必要的。|
并且引号不会嵌套,因此在整个内容周围加上引号可能不会按您期望的方式工作(例如,如果您不小心,该$2
awk 命令可能会在本地计算机上扩展,即使它看起来像在单引号)。
当事情像这样变得混乱时,最简单的方法有时是将远程命令作为此处文档而不是作为ssh
命令的参数传递。但是您需要在 here-document 分隔符周围加上引号,以防止$
本地 shell 完成各种扩展。像这样的东西:
ssh user@myserver.com <<'EOF'
echo $(ps -aux|grep -v "grep"|grep "/srv/adih/server/app.js"|awk '{print $2}')
EOF
注意:缩进远程命令时要小心,因为文本将按字面意思发送到远程计算机。如果您使用制表符缩进它,您可以将<<-
其用作此处的文档分隔符(例如<<-'EOF'
),它会删除前导制表符。
编辑:正如@tripleee 指出的那样,不需要多个grep
s,因为awk
它可以自己完成整个工作。也没有必要从结果中排除搜索命令(grep -v grep
),因为模式中的“/”字符需要转义,这意味着它不会匹配自己。所以您可以将管道简化为:
ps -aux | awk '/\/srv\/adih\/server\/app.js/ {print $2}'
现在,我一直假设实际目标是kill
相关的 pid,并且echo
只是为了测试。如果是这样的话,实际的命令最终是:
ssh user@myserver.com <<'EOF'
kill $(ps -aux | awk '/\/srv\/adih\/server\/app.js/ {print $2}')
EOF
如果这不正确,那么echo $( )
最好完全跳过整个事情。没有理由捕获管道的输出然后echo
它,只需运行它并让它直接输出。
如果pkill
(或类似的东西)可用,那么使用它会更简单。