Linux使用while循环同ssh命令导致只能遍历一次的问题

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux使用while循环同ssh命令导致只能遍历一次的问题相关的知识,希望对你有一定的参考价值。

异常

写一个脚本文件,先从hosts文件中读取所有的IP地址,再从publish-files文件夹中读取要发布的文件名,然后通过ssh命令去查找。但是只能处理第一个IP地址,下面的IP地址就不会接着遍历了。

错误代码

#!/bin/bash

# 第一步,获取存储在hosts文件中的远程服务器IP地址
cat hosts | while read host
do
   echo "远程服务器IP地址:$host"
   # 第二步,读取存储了待上传文件的目录publish-files下的所有文件
   for name in $(ls publish-files)
   do
      ssh root@$host "find / -name $name"
     # echo "$name"
   done
done

说明:

  • hosts是存放其他服务器IP地址的一个文件。
  • publish-files是一个目录,存放了一些文件。

原因

cat hosts | while read host中使用了重定向,hosts文件中的全部信息已经读取完毕并且重定向给while语句,所以在while循环中再一次调用read命令就会读取下一条记录。但是ssh命令正好会读取输入中的所有信息。如例:

#!/bin/bash

# 第一步,获取存储在hosts文件中的远程服务器IP地址
cat hosts | while read host
do
   echo "远程服务器IP地址:$host"
   ssh root@$host cat
done

其中cat命令会打印出hosts文件中的所有内容,也就是说调用完ssh命令后,输入中的数据已经被读取完了,自然不会执行下面的循环了。

解决

  • 第一种,给ssh命令输入重定向。用/dev/null来当ssh的输入,阻止ssh读取本地的标准输入内容。代码如下:
#!/bin/bash

# 第一步,获取存储在hosts文件中的远程服务器IP地址
cat hosts | while read host
do
   echo "远程服务器IP地址:$host"
   # 第二步,读取存储了待上传文件的目录publish-files下的所有文件
   for name in $(ls publish-files)
   do
      ssh root@$host "find / -name $name" < /dev/null #进行输入重定向
      echo "$name"
   done
done

  • 第二种,使用for命令循环
#!/bin/bash

# 第一步,获取存储在hosts文件中的远程服务器IP地址
for host in $(cat hosts)
do
   echo "远程服务器IP地址:$host"
   # 第二步,读取存储了待上传文件的目录publish-files下的所有文件
   for name in $(ls publish-files)
   do
      ssh root@$host "find / -name $name"
      echo "$name"
   done
done
  • 第三种,通过ssh命令的-n选项。
     -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 shad‐
             ows.cs.hut.fi, and the X11 connection will be automatically forwarded over an encrypted channel.  The ssh program will be put in the back‐
             ground.  (This does not work if ssh needs to ask for a password or passphrase; see also the -f option.)

代码如下:

#!/bin/bash

# 第一步,获取存储在hosts文件中的远程服务器IP地址
cat hosts | while read host
do
   echo "远程服务器IP地址:$host"
   # 第二步,读取存储了待上传文件的目录publish-files下的所有文件
   for name in $(ls publish-files)
   do
      ssh -n root@$host "find / -name $name"
      echo "$name"
   done
done

参考资料:

以上是关于Linux使用while循环同ssh命令导致只能遍历一次的问题的主要内容,如果未能解决你的问题,请参考以下文章

shell中使用while循环ssh的注意事项

带有 Paramiko 的嵌套 SSH 退出 while 循环

使用Java写出一万遍我爱你(while循环和do——while循环)

使用Java写出一万遍我爱你(while循环和do——while循环)

使用Java写出一万遍我爱你(while循环和do——while循环)

在while循环中运行ffmpeg会导致内存泄漏