如何在不重定向 stdin 的情况下使用脚本启动 ssh 会话?

How can I start an ssh session with a script without redirecting stdin?

我有一系列 bash 命令,其中一些带有交互式提示,我需要在远程计算机上 运行。对于不同的场景,我必须按特定顺序调用它们,所以我一直在尝试制作一个 bash 脚本来为我自动执行该过程。但是,似乎每种使用 bash 脚本启动 ssh 会话的方法都会导致 stdin 重定向到最初用于启动脚本的任何字符串或文件.

有没有一种方法可以指定在远程机器上执行某个脚本,还可以将 stdinssh 转发到本地机器以使用户能够与任何提示进行交互?

这是我必须阐明的要求列表。

  1. 运行 远程机器上的脚本。
  2. 在该远程脚本中间的某处是将提示输入的命令。示例:git commit 将调出 vim
    • 如果该命令是 git commit 并显示 vim,用户应该能够与 vim 交互,就好像它是 运行 在他们的本地机.
    • 如果该命令提示 [y/n] 响应,用户应该能够输入他们的答案。
  3. 用户输入必要的信息后——通过退出 vim 或在提示时按 return——脚本应该像往常一样继续 运行。
  4. 然后我的脚本将终止 ssh 会话。最终产品是为用户执行命令,而无需他们知道这是通过远程连接执行的。

我一直在用下面的脚本在远程机器上测试各种不同的方法运行。

#!/bin/bash
echo hello
vim
echo goodbye
exit

用户能够使用 vim 是至关重要的,然后,当用户完成后,"goodbye" 应该打印到屏幕上并且远程会话应该终止。

我试过将临时脚本上传到远程机器,然后 运行ning ssh user@host bash /tmp/myScript,但这似乎也完全接管了 stdin,因此无法让用户响应用户输入的提示。我已经尝试添加 -t-T 选项(我不确定它们是否不同),但我仍然得到相同的结果。

一位评论者提到使用 expectspawninteract,但我不确定如何结合使用这些工具来获得我想要的行为。似乎 interact 会导致用户获得对 stdin 的控制权,但是一旦用户退出 vim 就无法放弃它,以便让我的脚本继续执行。

我想要的行为是否可能?

好的,我想我已经找到我的问题了。我正在为 ssh 创建一个包装脚本,如下所示:

#!/bin/bash

tempScript="/tmp/myScript"
remote=user@host

commands=$(</dev/stdin)

cat <(echo "$commands") | ssh $remote "cat > $tempScript && chmod +x $tempScript" &&
ssh -t $remote $tempScript
errorCode=$?

ssh $remote << RM
  if [[ -f $tempScript ]]; then
    rm $tmpScript
  fi
RM

exit $errorCode

我在那里重定向 stdin,而不是 ssh。我应该在提出问题时提到这一点。我一遍又一遍地阅读那个脚本,但我想我只是忽略了那一行。删除该行完全解决了我的问题。

澄清一下,将我的脚本更改为以下完全解决了我的问题。

#!/bin/bash

tempScript="/tmp/myScript"
remote=user@host

commands="$@"

cat <(echo "$commands") | ssh $remote "cat > $tempScript && chmod +x $tempScript" &&
ssh -t $remote $tempScript
errorCode=$?

ssh $remote << RM
  if [[ -f $tempScript ]]; then
    rm $tmpScript
  fi
RM

exit $errorCode

一旦我更改了我的包装脚本,问题中描述的我的测试脚本就起作用了!我能够将 "hello" 打印到屏幕上, vim 出现并且我能够像往常一样使用它,然后一旦我退出 vim "goodbye" 就被打印出来并且 ssh客户端关闭。

问题的评论者一直在为我指明正确的方向。对不起,我只讲了一部分故事。

过去我曾多次寻找这个问题的解决方案,但从未找到完全令人满意的解决方案。管道连接到 ssh 会失去您的交互性。两个连接 (scp/ssh) 速度较慢,您的临时文件可能会被遗忘。而命令行上的整个脚本往往以逃避地狱告终。

最近我遇到命令行缓冲区大小通常很大(getconf ARG_MAX > 2MB 我看过)。这让我开始思考如何使用它并减轻转义问题。

结果是:

ssh -t <host> /bin/bash "<(echo "$(cat my_script | base64 | tr -d "\n")" | base64 --decode)" <arg1> ...

或使用此处文档和 cat:

ssh -t <host> /bin/bash $'<(cat<<_ | base64 --decode\n'$(cat my_script | base64)$'\n_\n)' <arg1> ...

我已经扩展了这个想法以生成一个完全可用的 BASH 示例脚本 sshx that can run arbitrary scripts (not just BASH), where arguments can be local input files too, over ssh. See here