我从Solaris文档获得了这个技巧,用于将ssh
公钥复制到远程主机(ssh-copy-id
在Solaris上不可用).
$ cat some_data_file | ssh user@host "cat >/tmp/some_data_file; some_shell_cmd"
似乎它可以适应更多涉及的事情.具体来说,我想some_shell_command
成为一个从本地发送到远程端执行的脚本,它将与本地键盘进行交互.
我尝试了stdin
从多个来源发送多个东西的方法.但是在本地shell中工作的一些东西不适用于ssh,而下面的一些东西并没有完全符合我的要求:
$ echo "abc" | cat <(echo "def") # echoes: def (I wanted abc\ndef) $ echo "abc" | cat < <(echo "def") # echoes: def (I wanted abc\ndef) $ echo "abc" | cat <<-EOF > echo $( EOF # messed with eval for the above but that was a problem too.
@chepner总结说,在一个ssh
命令中完成所有这些操作是不可行的,并解释了一个替代方案,这对我来说不适用于研究和调整他的答案.(我记录了这个帖子中的结果).没有它,必须运行多个ssh
,scp
默认情况下命令需要多次提示输入密码,这是一个主要障碍,因为我不能指望我在多用户环境中编写的脚本的所有用户都配置公钥授权也不会让他们不得不一遍又一遍地输入密码.
即使在使用该
ControlPersist
选项不可用的早期版本的OpenSSH时,此解决方案仍然有效.(本回答结束时的工作bash示例)
OpenSSH 3.9通过"控制主连接" (2005年)引入了会话多路复用.
但是,ControlPersist
直到OpenSSH 5.6(2010年发布)才推出该选项 .
会话多路复用对于最小化认证开销很有用.例如,如果您有一个脚本ssh
使用OpenSSH会话多路复用的任意组合运行多个不同的任务,则"控制主会话"进行一次身份验证,保持其连接打开,并且ssh相关命令通过引用来共享该连接其命名套接字在文件系统中的位置.通过会话多路复用,您可以避免多次输入密码(例如,在某些情况下,您无法依赖配置了公钥认证的用户).
大多数当前的解决方案(例如@Chepner的答案)需要使用scp
告知sftp
来保持控制主连接无限期地打开,或者持续一段特定的秒数,但是因为具有OpenSSH之前的系统没有该选项,并且升级它们可能不可行,要做什么?不幸的是,似乎没有太多关于它的文档或讨论在线.
OpenSSH
迟到会话多路复用场景,这意味着必须有一种替代方法来配置会话多路复用而不依赖于该ControlPersist
选项.我试图弄清楚如何,但最初遇到ssh会话过早终止并关闭所需的控制连接客户端会话的问题,或者,如果我保持连接打开(保持ssh控制主机处于活动状态),终端I/O被阻止,我的脚本会挂起!最终我发现了完成它的旗帜.
OpenSSH option ssh flag Purpose ------------------- --------- ----------------------------- -o ControlMaster=yes -M Establishes sharable connection -o ControlPath=path -S path Specifies path of connection's named socket -o ControlPersist=600 Keep shareable connection open 10 min. -o ControlPersist=yes Keep shareable connection open indefinitely -N Don't create shell or run a command -f Go into background after authenticating -O exit Closes persistent connection
ControlPersist form Equivalent Purpose ------------------- ---------------- ------------------------- -o ControlPersist=yes ssh -Nf Keep control connection open indefinitely -o ControlPersist=300 ssh -f sleep 300 Keep control connection open 5 min.
注:ssh
和ControlPersist
实施ControlPersist
不同的标志,而scp
不是在所有,所以,对于这些命令,标志sftp
总是必需的形式.
粗略的操作概述:
注意:此不完整的示例不会如图所示执行.
ctl=ssh -fNMS $ctl user@host # open control master connection ssh -S $ctl … # example of ssh over connection scp -o ControlPath=$ctl … # example of scp over connection sftp -o ControlPath=$ctl … # example of sftp over connection ssh -S $ctl -O exit # close control master connection
会话多路复用演示 (工作示例 - 仅验证一次):
注意:以下代码的样式很糟糕,例如"压缩和压缩",以避免回答中的滚动条.如果您精通shell并复制/粘贴/执行此示例,并且无法访问远程主机,请在"Host ...?"处输入localhost.提示.
#!/bin/bash # This script demonstrates ssh session multiplexing trap "[ -z "$ctl" ] || ssh -S $ctl -O exit $user@$host" EXIT # closes conn, deletes fifo read -p "Host to connect to? " host read -p "User to login with? " user BOLD="\n$(tput bold)"; NORMAL="$(tput sgr0)" echo -e "${BOLD}Create authenticated persistent control master connection:${NORMAL}" sshfifos=~/.ssh/controlmasters [ -d $sshfifos ] || mkdir -p $sshfifos; chmod 755 $sshfifos ctl=$sshfifos/$user@$host:22 # ssh stores named socket for open ctrl conn here ssh -fNMS $ctl $user@$host # Control Master: Prompts passwd then persists in background lcldir=$(mktemp -d /tmp/XXXX); echo -e "\nLocal dir: $lcldir" rmtdir=$(ssh -S $ctl $user@$host "mktemp -d /tmp/XXXX"); echo "Remote dir: $rmtdir" echo -e "${BOLD}Copy self to remote with scp:${NORMAL}" scp -o ControlPath=$ctl ${BASH_SOURCE[0]} $user@$host:$rmtdir echo -e "${BOLD}Display 4 lines of remote script, with ssh:${NORMAL}" echo "=====================================================================" echo $rmtdir | ssh -S $ctl $user@$host "dir=$(