Bash虽然读取循环早期破坏

时间:2008-12-06 16:24:26

标签: bash shell

我一直用这个来撞墙一段时间。

我想通过SSH连接到一组计算机并检查它们是否可用(接受连接而不使用)。我创建了一个小脚本tssh,它就是这样做的:

#!/bin/bash

host=$1
timeout=${2:-1}

ssh -qo "ConnectTimeout $timeout" $host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1"

此脚本可正常运行。如果出现连接问题则返回255,如果机器正忙则返回1,如果一切正常则返回0。如果有人知道更好的方法,请告诉我。

接下来我尝试使用while读取循环在我的机器上调用tssh,这就是出错的地方。一旦tssh返回0,循环就会退出,并且永远不会完成整个集合。

while read nu ; do tssh "MYBOXES$nu" ; done < <(ruby -e '(0..20).each { |i| puts i }')

起初我认为这是一个子壳问题,但显然不是。 任何帮助,以及对风格/内容的评论,将不胜感激! 我知道当我发现原因时我会踢自己......

9 个答案:

答案 0 :(得分:40)

克里斯是对的。循环中断的来源是使用stdin的SSH,但是使用循环方法的枪是正确的。

如果要循环输入(例如带有主机名列表的文件)并调用SSH,则需要传递-n参数,否则基于输入的循环将失败。

while read host; do
  ssh -n $host "remote command" >> output.txt
done << host_list_file.txt

答案 1 :(得分:33)

在构造

something | 
while read x; do 
    ssh ...
done

while循环看到的标准输入是something的输出。

ssh的默认行为是读取标准输入。这允许你做像

这样的事情
cat id_rsa.pub | ssh new_box "cat - >> ~/.ssh/authorized_keys"

现在,话虽如此,当读取第一个值时,第一个ssh命令将读取something的整个输入。然后,在ssh完成时,没有输出,read停止。

修正案为ssh -n ...,例如

cat /etc/hosts | awk '{print $2}' | while read x; do
    ssh -n $x "do_something_on_the_machine"
done

答案 2 :(得分:7)

我今天碰到了这个 - rsh和/或ssh可以打破一段时间读取循环,因为它使用stdin。我把一个-n放到ssh行中,这阻止了它尝试使用stdin并修复了问题。

答案 3 :(得分:6)

大多数答案都是针对ssh的。其他命令也劫持stdin并且没有-n选项。这应该解决任何其他命令。这也适用于ssh。

while read x; do 
    # Make sure command does not hijack stdin
    echo "" | command $x
done < /path/to/some/file

答案 4 :(得分:4)

不知道它是否会有所帮助,但更清晰的写作方式

for nu in `ruby -e '(0..20).each { |i| puts i}'`; do
  tssh "MYBOXES$nu" 
done

答案 5 :(得分:3)

我也不确定它失败的原因,但我喜欢xargsseq

seq 0 20 | xargs -n1 tssh MYBOXES

答案 6 :(得分:3)

正如Kaii所说,调用ruby或seq(在BSD或OSX机器上不起作用)只是输出一系列数字真是太过分了。如果您对使用bash感到满意,可以:

for i in {0..20}; do
    # command
done

我相信这应该适用于bash 2.05b及以上版本。

答案 7 :(得分:2)

我不能相信这是0的结果打破了你的循环,你可以通过在循环中用“/ bin / true”替换你的tssh命令来测试,这也返回0。

关于样式我不明白为什么一个简单的循环shell脚本需要ruby,perl,seq或jot或者不在我的* BSD上的任何其他二进制文件。

你也可以使用内置for loop构造的shell,它至少在ksh,bash中起作用:

for ((i=0; $i<=20; i++)); do
    tssh "MYBOXES$i"
done

答案 8 :(得分:2)

谈论“抢劫彼得要付保罗”的问题。我已经挣扎了好几个小时才弄清楚为什么我的ssh在读取循环时杀了我的东西。

坚持使用while循环并同时保持ssh的另一种方法是使用“-n”开关在ssh / dev / null上创建STDIN。对我来说就像一个魅力:

#!/bin/bash
[...]
something|while read host
   do
      ssh -nx ${host} fiddleAround
   done

(我倾向于总是使用“-x”以避免浪费时间在隧道中协商X.)