【问题介绍】
下面这个脚本,总是执行一次就退出循环体
# cat test.sh
while read line
do
echo $line
ssh -i SSHKey 10.204.188.3 'date'
done << EOF
1
2
3
4
5
EOF
输出
# ./test.sh
1
Tue Nov 5 14:55:17 JST 2013
【分析过程】
这个脚本是最基本的while循环体,几乎不存在语法,输入方面异常的可能。那么问题肯定出在ssh这句上面。
ssh (SSH client) is a program for logging into a remote machine and for executing commands on a remote machine. It is intended to replace rlogin andrsh, and provide secure encrypted communications between two untrusted hosts over an insecure network. X11 connections and arbitrary TCP ports can also beforwarded over the secure channel
上面是SSH工具的描述,是一个用来远程执行命令的工具,将命令送到远程机器去执行,并返回输出到本地的标准输出。
问题来了,两个EOF之间明明有5行,为何只读一行,while就判断到文件末尾,进而退出了? 剩下的几行(2~5)内容被谁读取了?
答案就是ssh。
【验证过程】
修改脚本验证上述结论。
# cat test.sh
while read line
do
echo $line
#ssh -i SSHKey 10.204.188.3 'date'
ssh -i SSHKey 10.204.188.3 'read sshVar && echo "ssh output:"$sshVar'
done << EOF
1
2
3
4
5
EOF
输出
# ./test.sh
1
ssh output:2
从上面可以看出ssh确实有读取剩下的内容。如何解决问题呢?检查ssh选项,发现
-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background. A
common trick is to use this to run X11 programs on a remote machine. For example, ssh -n shadows.cs.hut.fi emacs & will start
an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically forwarded over an encrypted channel. The ssh pro-
gram will be put in the background. (This does not work if ssh needs to ask for a password or passphrase; see also the -f
option.)
可以说这个选项是专门用来解决这个问题的。用/dev/null来当ssh的输入,阻止ssh读取本地的标准输入内容。进一步修改脚本
# cat test.sh
while read line
do
echo $line
#ssh -i SSHKey 10.204.188.3 'date'
ssh -i SSHKey 10.204.188.3 -n 'read sshVar && echo "ssh output:"$sshVar '
done << EOF
1
2
3
4
5
EOF
输出
# ./test.sh
1
2
3
4
5
终于达到预期结果,ssh不再读本地输入的内容。