我有一个 bash 脚本,用于从远程计算机(我无法控制)复制两个文件,存储在需要访问的路径中root
。这里是:
ssh administrator@host "mkdir ${DIR}"
ssh -t administrator@host "sudo su - root -c 'cp /path/for-root-only/data1/${FILENAME} ${DIR}/'"
ssh administrator@host "mv ${DIR}/${FILENAME} ${DIR}/data1-${FILENAME}"
ssh -t administrator@host "sudo su - root -c 'cp /path/for-root-only/data2/${FILENAME} ${DIR}/'"
scp administrator@host:$DIR/{${FILENAME},data1-${FILENAME}} .
ssh administrator@host "rm -r ${DIR}"
该脚本多次提示输入相同的密码。我尝试通过此处的文档合并所有命令,如下所示ssh -t
:
ssh -t administrator@host << EOF
mkdir ${DIR}
sudo su - root -c 'cp /path/for-root-only/data1/${FILENAME} ${DIR}/'
mv ${DIR}/${FILENAME} ${DIR}/data1-${FILENAME}
sudo su - root -c 'cp /path/for-root-only/data2/${FILENAME} ${DIR}/'
EOF
scp administrator@host:$DIR/{${FILENAME},data1-${FILENAME}} .
ssh administrator@host "rm -r ${DIR}"
但有这样的警告:
伪终端不会被分配,因为 stdin 不是终端。
我想问是否有正确的方法来编写该脚本以尽量减少密码提示的次数
答案1
打开一次 SSH 连接,然后使用它。 OpenSSH 的这一功能称为主连接。看使用已建立的 SSH 通道
ssh_control_socket="$(mktemp)"
ssh -o ControlPath="$(ssh_control_socket)" -o ControlMaster=yes -o ControlPersist=yes administrator@host "mkdir ${DIR}"
# other commands using ssh (ssh, scp, rsync, …): pass the same ControlPath option
ssh -o ControlPath="$(ssh_control_socket)" -t administrator@host "…"
rsync -e "ssh -o 'ControlPath=$(ssh_control_socket)'" …
ssh -o ControlPath="$(ssh_control_socket)" administrator@host -O exit
rm -f "$(ssh_control_socket)"
令人烦恼的是,您需要在每个 SSH 调用上显式传递一个选项(它是用于在每个调用和进行实际连接的原始 SSH 客户端ControlPath
之间进行通信的文件的名称)。ssh
这里我传递了一个显式的套接字名称,以便脚本是独立的。如果依赖~/.ssh/config
是可以接受的,那么将此行添加到您的~/.ssh/config
:
ControlPath ~/.ssh/%l_%h_%p_%r.multiplex
这使得每个 SSH 客户端都能够检查是否存在现有连接。除非有监听主连接,否则该功能实际上不会被使用,您仍然需要在第一个连接上传递-o ControlMaster=yes
(或-M
简称),即您的脚本可以是
# Open the shared connection
ssh -M -o ControlPersist=yes administrator@host :
# … all SSH-relying commands in their basic form, they will go via the shared connection …
# Close the shared connection
ssh -O exit administrator@host
答案2
你不需要这样做这里文档(这就是该<<
内容的作用)。
你可以简单地做ssh remotehost "command1; command2 ; command3"
例如
% ssh localhost "date ; uptime ; echo hello"
sweh@localhost's password:
Tue Jul 19 08:07:48 EDT 2016
08:07:48 up 15 days, 31 min, 3 users, load average: 0.33, 0.33, 0.40
hello
然而scp
,不会轻易地以这种方式合并。
所以你可能想考虑使用公钥认证而不是密码身份验证(也称为“ssh 密钥”)。通常这样的事情就是这样自动化的。