【问题标题】:How can I start an ssh session with a script without redirecting stdin?如何在不重定向标准输入的情况下使用脚本启动 ssh 会话?
【发布时间】:2016-08-30 20:37:46
【问题描述】:

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

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

这是我必须阐明我正在尝试做什么的要求列表。

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

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

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

用户能够使用vim 至关重要,然后,当用户完成时,应在屏幕上打印“再见”并终止远程会话。

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

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

我想要的行为是否可能?

【问题讨论】:

  • @anishsane 是的,我使用该标志通过带有heredoc 的ssh 发送命令,但这完全接管了标准输入,并且不允许我与出现的任何提示进行交互稍后在执行中。 vim 对此特别不满意——没有占据整个屏幕并拒绝所有输入。我可以在键盘出现时用键盘输入,但这只会导致屏幕顶部出现随机转义码,根本不会影响 vim 实例。
  • 如果你重定向stdin,你期望它是怎样交互的?
  • 是的,这正是问题所在。如何在不重定向 stdin 的情况下做到这一点?
  • 要么使用expectspawn ssh 并在命令之间使用interact,要么创建一个长字符串并使用ssh user@host command args 语法或将heredoc 内容scp 到远程系统并从那里执行文件...
  • ssh -t user@host bash /tmp/myscr ?

标签: bash unix vim ssh expect


【解决方案1】:

过去我曾多次寻找解决此问题的方法,但从未找到完全令人满意的解决方案。进入 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,它可以运行任意脚本(不仅仅是 BASH),其中参数也可以是本地输入文件,通过 ssh。见here

【讨论】:

    【解决方案2】:

    好的,我想我找到了我的问题。我正在为 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 客户端关闭。

    问题的评论者一直在为我指明正确的方向。很抱歉我只讲了我的部分故事。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 2020-01-07
      • 1970-01-01
      相关资源
      最近更新 更多