![引用命令中的反引号评估问题,在 su -c 中,在 Heredoc 中,馈入 2 层 ssh](https://linux22.com/image/168586/%E5%BC%95%E7%94%A8%E5%91%BD%E4%BB%A4%E4%B8%AD%E7%9A%84%E5%8F%8D%E5%BC%95%E5%8F%B7%E8%AF%84%E4%BC%B0%E9%97%AE%E9%A2%98%EF%BC%8C%E5%9C%A8%20su%20-c%20%E4%B8%AD%EF%BC%8C%E5%9C%A8%20Heredoc%20%E4%B8%AD%EF%BC%8C%E9%A6%88%E5%85%A5%202%20%E5%B1%82%20ssh.png)
我有以下间接链:
ssh -t root@host1 ssh host2 << EOF\nsu - user2 -c 'kill `cat ~/file_with_pid`'\nEOF
最后我需要的只是以 user2 的身份终止主机 2 上的一个进程(从文件中读取 pid)。除了单引号之间的部分外,我不能改变太多
'kill `cat ~/file_with_pid`'
因此我不能简单地
ssh user2@host2 'kill `cat ~/file_with_pid`'
我的问题是~
文件路径中的 home 被扩展到错误的 home。这可能与反引号的求值时间有关(由于命令链很长,我不太确定这种情况何时发生)。
如何更改单引号中的部分以获得我想要的内容?
(注意:我无法对 home 进行硬编码,因为我可能会host2
以 user 的身份在任意位置执行此操作user2
,因此我希望user2
每次都能确定 'home )。
答案1
-J
正如 @pLumo 所建议的,您可以通过使用ssh 的 (“JumpHost”) 选项来摆脱一些引用地狱:
ssh -J root@host1 root@host2 "su user2 -c 'kill \"\$(cat ~/file_with_pid)\"'"
或者,使用此处文档:
ssh -J root@host1 -T root@host2 <<'EOT'
su user2 -c 'kill "$(cat ~/file_with_pid)"'
EOT
注意<<'EOT'
代替<<EOT
;引用结束标记可以防止变量、反引号等在此处文档中展开。
一般情况下,它-T
会阻止 ssh 分配伪 tty,在这种情况下,它将阻止 ssh 警告您它尚未分配伪终端。如果出于某种原因你确实需要一个伪终端,请使用两个-t
选项来强制 ssh 分配一个,即使当地的stdin 不是 tty。并exit
在此处文档中添加一个:
ssh -J root@host1 -tt root@host2 <<'EOT'
su user2 -c 'kill "$(cat ~/file_with_pid)"'
exit
EOT
如果您需要连接到另一个端口而不是跳转主机上的 22,您应该使用以下-J user@host1:port
形式;该-p
选项适用于host2
:
ssh -J root@host1:port1 -p port2 root@host2 "su user2 -c 'kill \"\$(cat ~/file_with_pid)\"'"
我不知道有任何快捷方式选项可以让您为跳转主机使用不同的身份(如-i
);看来您必须为此使用配置文件。
在您的示例中,EOF\nsu
未加引号的只是EOFnsu
, not EOF<newline>su
(即使是,这也不起作用)。
但是重定向标准输入ssh
(如此处<<
文档所做的那样)将阻止第二台主机上的任何交互式身份验证,因此即使这样也无法修复您的示例。