Bash while read:输出问题



更新:首次发行:有一个while read循环打印每一行被读取答案:放一个完成<<<" $ var "后续发行:我可能需要一些关于SHELL代码的解释:我有这个:

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>

ip地址

我做了一个"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

为什么它不能处理这个?

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

done<"$temp_ip"

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

done<<<"$temp_ip"

注意变量被放在双引号内。这样可以保护数据不受shell分词的影响,因为分词会导致用空格替换新的行字符。

更多细节

在bash中,像<"$temp_ip"这样的表达式称为重定向。在本例中,In意味着while循环将从名为$temp_ip的文件中获得其标准输入。

表达式<<<"$temp_ip"称为这里字符串。在本例中,这意味着while循环将从变量$temp_ip中的数据中获取标准输入。

man bash中重定向和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) | 
while read ip codesite
do
...
done

如果您想提高性能并并行运行5000个snmpget中的一些,我建议使用GNU parallel(在这里),像这样:

$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和代码站点参数。

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

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

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个后台进程

由于您似乎不喜欢我对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,它将等待所有启动的进程完成。

最新更新