如何在不重定向 stdin 的情况下使用脚本启动 ssh 会话?
How can I start an ssh session with a script without redirecting stdin?
我有一系列 bash 命令,其中一些带有交互式提示,我需要在远程计算机上 运行。对于不同的场景,我必须按特定顺序调用它们,所以我一直在尝试制作一个 bash 脚本来为我自动执行该过程。但是,似乎每种使用 bash 脚本启动 ssh
会话的方法都会导致 stdin
重定向到最初用于启动脚本的任何字符串或文件.
有没有一种方法可以指定在远程机器上执行某个脚本,还可以将 stdin
到 ssh
转发到本地机器以使用户能够与任何提示进行交互?
这是我必须阐明的要求列表。
- 运行 远程机器上的脚本。
- 在该远程脚本中间的某处是将提示输入的命令。示例:
git commit
将调出 vim
。
- 如果该命令是
git commit
并显示 vim
,用户应该能够与 vim
交互,就好像它是 运行 在他们的本地机.
- 如果该命令提示
[y/n]
响应,用户应该能够输入他们的答案。
- 用户输入必要的信息后——通过退出
vim
或在提示时按 return——脚本应该像往常一样继续 运行。
- 然后我的脚本将终止 ssh 会话。最终产品是为用户执行命令,而无需他们知道这是通过远程连接执行的。
我一直在用下面的脚本在远程机器上测试各种不同的方法运行。
#!/bin/bash
echo hello
vim
echo goodbye
exit
用户能够使用 vim
是至关重要的,然后,当用户完成后,"goodbye" 应该打印到屏幕上并且远程会话应该终止。
我试过将临时脚本上传到远程机器,然后 运行ning ssh user@host bash /tmp/myScript
,但这似乎也完全接管了 stdin
,因此无法让用户响应用户输入的提示。我已经尝试添加 -t
和 -T
选项(我不确定它们是否不同),但我仍然得到相同的结果。
一位评论者提到使用 expect
、spawn
和 interact
,但我不确定如何结合使用这些工具来获得我想要的行为。似乎 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。
我有一系列 bash 命令,其中一些带有交互式提示,我需要在远程计算机上 运行。对于不同的场景,我必须按特定顺序调用它们,所以我一直在尝试制作一个 bash 脚本来为我自动执行该过程。但是,似乎每种使用 bash 脚本启动 ssh
会话的方法都会导致 stdin
重定向到最初用于启动脚本的任何字符串或文件.
有没有一种方法可以指定在远程机器上执行某个脚本,还可以将 stdin
到 ssh
转发到本地机器以使用户能够与任何提示进行交互?
这是我必须阐明的要求列表。
- 运行 远程机器上的脚本。
- 在该远程脚本中间的某处是将提示输入的命令。示例:
git commit
将调出vim
。- 如果该命令是
git commit
并显示vim
,用户应该能够与vim
交互,就好像它是 运行 在他们的本地机. - 如果该命令提示
[y/n]
响应,用户应该能够输入他们的答案。
- 如果该命令是
- 用户输入必要的信息后——通过退出
vim
或在提示时按 return——脚本应该像往常一样继续 运行。 - 然后我的脚本将终止 ssh 会话。最终产品是为用户执行命令,而无需他们知道这是通过远程连接执行的。
我一直在用下面的脚本在远程机器上测试各种不同的方法运行。
#!/bin/bash
echo hello
vim
echo goodbye
exit
用户能够使用 vim
是至关重要的,然后,当用户完成后,"goodbye" 应该打印到屏幕上并且远程会话应该终止。
我试过将临时脚本上传到远程机器,然后 运行ning ssh user@host bash /tmp/myScript
,但这似乎也完全接管了 stdin
,因此无法让用户响应用户输入的提示。我已经尝试添加 -t
和 -T
选项(我不确定它们是否不同),但我仍然得到相同的结果。
一位评论者提到使用 expect
、spawn
和 interact
,但我不确定如何结合使用这些工具来获得我想要的行为。似乎 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。