假设我想通过机器 A 连接到机器 B。据我所知,有多种方法可以实现这一点,例如
ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
# Some commands in machine B
END_OF_SSH_CONNECTION
或者
ssh -T user@machineA << END_OF_MACHINE_A
ssh -T machine B << END_OF_MACHINE_B
# Some commands in machine B
END_OF_MACHINE_B
END_OF_MACHINE_A
但是,我不清楚如何启动一个交互式 shell,以便用户可以在连接到机器 B 时键入命令。例如,这样做:
ssh user@machineA -t 'bash -l -c "bash"'
这也确实有效:
ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'
但是,以下操作不起作用:
ssh -J user@machineA user@machineB -t 'sudo apt-get update; bash -l -c "bash"'
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Connection to machineB closed.
以下情况也不适用:
ssh -J user@machineA user@machineB -t 'if [ 1 -eq 1 ]; then bash -l -c "bash"; fi'
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Connection to machineB closed.
我也尝试过这个:
ssh -T -J user@machineA user@machineB << EOF
# Some commands on machineB
# Check whether apache2 has been correctly installed
if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ];
then
printf "done\n";
else
printf "fail\nStarting an interactive shell: enter exit to quit\n";
bash -l -c "bash";
fi
EOF
最后一个版本几乎可以工作(即它不返回任何错误),但是它并没有像我期望的那样启动一个用户可以输入命令的交互式 shell。
我希望有人能帮助我。提前致谢。
答案1
感谢@attie的帮助。我稍微修改了你提出的代码,并在下面进行了报告
#!/usr/bin/env bash ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF" if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then echo "done"; else echo "fail, starting an interactive shell"; bash -l -c "bash"; fi EOF ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
到这个,甚至不需要写入外部文件。
#!/usr/bin/env bash
ssh -T -J user@machineA user@machineB << "EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q "ok installed"; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
我基本上错过了周围的引号EOF
,用于避免尝试扩大领域${Status}
。
答案2
如果你想在远程主机上运行脚本和获得一个交互式 shell,那么你有两个选择:
- 将整个脚本放入命令行参数中
ssh
。 - 将脚本推送到远程主机(例如:使用
scp
或ssh
),然后执行它(例如:使用ssh
)
1. Args 中的脚本
你的最后一个例子接近于“长的“对于这种方法,但你可以通过使用mapfile
( 中的内置函数bash
)。请注意引用"EOF"
以避免尝试扩展${Status}
。
mapfile -t SCRIPT <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "${SCRIPT[@]}"
2. 推送脚本,然后运行
mktemp
使用后清理可获得加分。"EOF"
再次引用注释。
根据您提供的错误消息之一(大约exec
,请参阅下文了解更多),这种使用cat >/tmp/myscript
可能行不通。
ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
第一步应该始终是尝试将问题分解为最简单的形式......对于你的最后咒语,请尝试以下步骤:
ssh -T user@machineA << EOF
bash -l -c "bash";
EOF
发生了什么?您将收到来自远程主机的任何欢迎消息,但会话会立即无提示地结束,没有任何错误。
改变-T
(明确禁用PTY 分配)为-t
(强制 PTY 分配)提供了正确方向的提示:
ssh -t user@machineA << EOF
bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
这表明您正在使用stdin
提供脚本,然后还尝试将该脚本stdin
(管道,而不是终端)连接到远程 PTY。
因此让我们消除这个stdin
因素:
ssh -t user@machineA bash -l -c "bash"
并且它有效!
从根本上来说不能与脚本和终端共享标准输入。
至于其他错误:
E: Command line option 'l' [from -l] is not understood in combination with the other options.
再次,将其分解以找到问题。不幸的是,这些命令对我来说是有效的,我怀疑是因为我可以访问的系统正在使用sh -c "${ARGS}"
或类似的东西。但是,您提供的另一个错误给出了提示:
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
看起来您的系统正在使用exec
作为参数给出的命令来运行ssh
...,这意味着 shell 无法像您希望的那样为您处理if
或处理类似的事情 - 因此路径上没有二进制文件并且它会失败。;
if
sudo
同样,所有参数都一次性给出:
sudo
apt-get
update;
bash
-l
-c
"bash"
果然,sudo
的(列表)参数与(登录类)-l
互斥。-c