【问题标题】:Bash while read : output issue读取时重击:输出问题
【发布时间】:2014-07-11 03:08:46
【问题描述】:

更新: 初始问题: 有一个 while read 循环打印读取的每一行 答案:把 done

temp_ip=$($mysql --skip-column-names -h $db_address -u $db_user -p$db_passwd $db_name -e "select ip_routeur,code_site from $db_vtiger_table where $db_vtiger_table.ip_routeur NOT IN (select ip from $db_erreur_table);")

得到的结果如下所示:

<ip1>   <site1>
<ip2>   <site2>
<ip3>   <site3>
<ip4>   <site4>

最多 5000 个 ip_address

我做了一个“while循环”:

while [ `find $proc_dir -name snmpproc* | wc -l` -ge "$max_proc_snmpget" ];do
    {
         echo "sleeping, fping in progress";
         sleep 1;
    }
done
temp_ip=$($mysql --skip-column-names -h $db_address -u $db_user -p$db_passwd $db_name -e "select ip_routeur,code_site from $db_vtiger_table where $db_vtiger_table.ip_routeur NOT IN (select ip from $db_erreur_table);")
while read ip codesite;do
{
    sendSNMPGET $ip $snmp_community $code_site &
}
done<<<"$temp_ip"

sendSNMPGET 函数是:

sendSNMPGET() {
touch $procdir/snmpproc.$$
hostname=`snmpget -v1 -c $2 $1 sysName.0`
if [ "$hostname" != "" ]
then
    echo "hi test"
fi
rm -f $procdir/snmpproc.$$

$max_proc_snmpget 设置为 30 执行时,读取正常,屏幕上不再打印,但子进程似乎迷失方向

hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
hi
./scan-snmp.sh: fork: Resource temporarily unavailable
./scan-snmp.sh: fork: Resource temporarily unavailable
./scan-snmp.sh: fork: Resource temporarily unavailable
./scan-snmp.sh: fork: Resource temporarily unavailable

为什么它不能处理这个?

【问题讨论】:

  • 它这样做是因为您创建了太多进程。尝试查看 $$ 的值,看看它是否正在改变......

标签: sql bash loops for-loop while-loop


【解决方案1】:

如果temp_ip 包含您要读取的文件的名称,则使用:

done<"$temp_ip"

在您的情况下,temp_ip 似乎不是文件名,而是包含您想要的实际数据。在这种情况下,请使用:

done<<<"$temp_ip"

注意变量放在双引号内。这可以保护数据免受 shell 的分词,这会导致用空格替换换行符。

更多详情

在 bash 中,像&lt;"$temp_ip" 这样的表达式称为重定向。在这种情况下,in 意味着while 循环将从名为$temp_ip 的文件中获取其标准输入。

表达式&lt;&lt;&lt;"$temp_ip" 被称为这里的字符串。在这种情况下,这意味着while 循环将从变量$temp_ip 中的数据中获取其标准输入。

有关重定向和此处字符串的更多信息,请参见man bash。

【讨论】:

  • 如果你能解释一下&lt;&lt;&lt;和&lt;和&lt;&lt;&lt;有什么区别!
  • echo Hello &gt; a,然后:cat &lt; a 将打印Hello,而cat &lt;&lt;&lt; a 将打印a。
  • 谢谢,工作!但现在有另一个问题...更新线程
  • @Gui 如果你原来的问题解决了,请不要把你的问题改得面目全非。留下这个问题,以便当前的答案是相关的,如果您需要其他方面的帮助,请提出一个新问题。
  • 嗯,这是这个答案的后续问题,我想它可以在同一个线程中解决......不是吗?
【解决方案2】:

或者您可以直接解析初始命令的输出:

$mysql --skip-column-names -h $db_address -u $db_user -p$db_passwd $db_name -e "select ip_routeur,code_site from $db_vtiger_table where $db_vtiger_table.ip_routeur NOT IN (select ip from $db_erreur_table) | \
while read ip codesite
do
...
done

如果您想提高性能并并行运行 5,000 个 SNMPGET 中的一些,我建议您使用 GNU Parallel (here),如下所示:

$mysql --skip-column-names -h $db_address -u $db_user -p$db_passwd $db_name -e "select ip_routeur,code_site from $db_vtiger_table where $db_vtiger_table.ip_routeur NOT IN (select ip from $db_erreur_table) | parallel -k -j 20 -N 2 sendSNMPGET {1} $snmp_community {2}

-k 将保持并行输出有序。 -j 20 一次最多可以并行运行 20 个 SNMPGET。 -N 2 表示从每个作业的 mysql 输出中获取 2 个参数(即 ip 和 codesite)。 {1} 和 {2} 是您的 ip 和 codesite 参数。

http://www.gnu.org/software/parallel/

【讨论】:

    【解决方案3】:

    我建议不要存储结果值而是直接使用它:

    while read ip codesite
    do
        sendSNMPGET "$ip" "$snmp_community" "$code_site" &
    done < <(
      "$mysql" --skip-column-names -h "$db_address" -u "$db_user" -p"$db_passwd" "$db_name" \
             -e "select ip_routeur,code_site from $db_vtiger_table where $db_vtiger_table.ip_routeur NOT IN (select ip from $db_erreur_table);")
    

    这样你在一个子shell中启动mysql命令并使用它的输出作为while循环的输入(类似于管道,这里也是一个选项)。

    但我发现该代码存在一些问题:如果您真的在后台启动每个 sendSNMPGET 命令,您很快就会给您的计算机带来大量负载。对于您读取的每一行,都会启动另一个活动的后台进程。这会使您的机器速度减慢到无法使用的程度。

    我建议一次不要运行超过 20 个后台进程。

    【讨论】:

      【解决方案4】:

      由于您似乎不喜欢我对 GNU Parallel 的回答,我将向您展示一种无需安装即可并行执行的非常简单的方法...

      #!/bin/bash
      MAX=8
      j=0
      while read ip code
      do
         (sleep 5; echo $ip $code) &   # Replace this with your SNMPGET
         ((j++))
         if [ $j -eq $MAX ]; then
            echo -n Pausing with $MAX processes...
            j=0
            wait
         fi
      done < file
      wait
      

      这会启动最多 8 个进程(您可以更改它),然后等待它们完成,然后再启动另一个 8 个。在第二个中,其他受访者已经向您展示了如何将您的 mysql 内容输入到循环中以脚本的最后一行...

      关键是wait,它将等待所有启动的进程完成。

      【讨论】:

      • 好吧,对不起,我搜索了 Parallel,但无法在 Redhat 上安装它。另外,这会在服务器上移动时引起一些麻烦(因为我不会在场...)我尝试了您的解决方案,它正在工作,我只需将 done
      猜你喜欢
      • 1970-01-01
      • 2015-06-12
      • 1970-01-01
      • 2021-08-09
      • 2020-04-18
      • 1970-01-01
      • 2014-12-05
      • 1970-01-01
      • 2011-09-10
      相关资源
      最近更新 更多