1. Args 中的脚本

1. Args 中的脚本

假设我想通过机器 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,那么你有两个选择:

  1. 将整个脚本放入命令行参数中ssh
  2. 将脚本推送到远程主机(例如:使用scpssh),然后执行它(例如:使用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同样,所有参数都一次性给出:

  1. sudo
  2. apt-get
  3. update;
  4. bash
  5. -l
  6. -c
  7. "bash"

果然,sudo的(列表)参数与(登录类)-l互斥。-c

相关内容