我需要几个网页中包含的整数之和。 getPages()
解析整数并将其设置为$subTotal
。在后台的for循环中调用getPages()
,但如何获得$subTotal
的总和?这是一个副壳问题吗?
这是我到目前为止所尝试过的。
#!/bin/bash
total=0
getPages(){
subTotal=$(lynx -dump http://"$(printf "%s:%s" $1 $2)"/file.html | awk -F, 'NR==1 {print $1}' | sed 's/\s//g')
total=$(($total+$subTotal))
echo "SubTotal: " $subTotal "Total: " $total
}
# /output/ SubTotal: 22 Total: 22
# /output/ SubTotal: 48 Total: 48 //Note Total should be 70
ARRAY=(
'pf2.server.com:6599'
'pf5.server.com:1199'
...
)
for server in ${ARRAY[@]} ; do
KEY=${server%%:*}
VALUE=${server##*:}
getPages $KEY $VALUE &
done
wait
echo $total
exit 0
# /output/ 0
任何建议表示赞赏。
答案 0 :(得分:4)
是的,这是一个替代问题。在... &
列表中执行的所有内容(即您的getPages $KEY $VALUE &
)都在子shell中执行,这意味着那里的变量更改不会影响父shell。
我认为可以使用coprocesses(即通过流进行通信),或者使用GNU parallel或pexec来做某事。
以下是pexec
的示例,使用默认输出从单个进程进行通信。我使用了一个更简单的命令,因为您列出的服务器无法从此处访问。这会对某些网页上的行进行计数并对其进行总结。
ARRAY=(
'www.gmx.de:80'
'www.gmx.net:80'
'www.gmx.at:80'
'www.gmx.li:80'
)
(( total = 0 ))
while read subtotal
do
(( total += subtotal ))
echo "subtotal: $subtotal, total: $total"
done < <(
pexec --normal-redirection --environment hostname --number ${#ARRAY[*]} \
--parameters "${ARRAY[@]}" --shell-command -- '
lynx -dump http://$hostname/index.html | wc -l'
)
echo "total: $total"
我们在这里使用一些技巧:
<( ... )
)和输入重定向(<
)而不是简单的管道。(( ... ))
算术表达式命令中进行算术运算。我可以使用let
,但是我必须引用所有内容或避免使用空格。 (你的total=$(( total + subtotal ))
也会奏效。)pexec
的选项:
--normal-redirection
表示将子进程中的所有输出流重定向到pexec
的输出流。 (如果两个进程想要同时写入,我不确定这会导致一些混淆。)--environment hostname
将每次执行的不同参数作为环境变量传递。否则它将是一个简单的命令行参数。--number ${#ARRAY[*]}
(在我们的例子中得到--number 4
)确保所有进程将并行启动,而不是只有我们有CPU或其他启发式启动。 (这适用于网络往返工作。对于CPU绑定或带宽绑定的东西,数量越小越好。)--shell-command
确保命令将由shell评估,而不是尝试直接执行它。这是必要的,因为那里有管道。--parameters "${ARRAY[@]}"
列出了实际的参数 - 即数组的元素。对于他们每个人,将启动一个单独的命令版本。--
之后命令 - 作为单个'
引用的字符串,以避免外壳对$hostname
的过早解释。该命令可以简单地下载文件并将其传递给wc -l
,计算行数。示例输出:
subtotal: 1120, total: 1120
subtotal: 968, total: 2088
subtotal: 1120, total: 3208
subtotal: 1120, total: 4328
total: 4328
这是ps -f
在运行时的(部分)输出:
2799 pts/1 Ss 0:03 \_ bash
5427 pts/1 S+ 0:00 \_ /bin/bash ./download-test.sh
5428 pts/1 S+ 0:00 \_ /bin/bash ./download-test.sh
5429 pts/1 S+ 0:00 \_ pexec --number 4 --normal-redirection --environment hostname --parame...
5430 pts/1 S+ 0:00 \_ /bin/sh -c ? lynx -dump http://$hostname/index.html | wc -l
5434 pts/1 S+ 0:00 | \_ lynx -dump http://www.gmx.de:80/index.html
5435 pts/1 S+ 0:00 | \_ wc -l
5431 pts/1 S+ 0:00 \_ /bin/sh -c ? lynx -dump http://$hostname/index.html | wc -l
5436 pts/1 S+ 0:00 | \_ lynx -dump http://www.gmx.net:80/index.html
5437 pts/1 S+ 0:00 | \_ wc -l
5432 pts/1 S+ 0:00 \_ /bin/sh -c ? lynx -dump http://$hostname/index.html | wc -l
5438 pts/1 S+ 0:00 | \_ lynx -dump http://www.gmx.at:80/index.html
5439 pts/1 S+ 0:00 | \_ wc -l
5433 pts/1 S+ 0:00 \_ /bin/sh -c ? lynx -dump http://$hostname/index.html | wc -l
5440 pts/1 S+ 0:00 \_ lynx -dump http://www.gmx.li:80/index.html
5441 pts/1 S+ 0:00 \_ wc -l
我们可以看到,在我的单处理器系统中,所有内容都尽可能并行运行。
答案 1 :(得分:0)
使用GNU Parallel的较短版本:
ARRAY=(
'www.gmx.de:80'
'www.gmx.net:80'
'www.gmx.at:80'
'www.gmx.li:80'
)
parallel lynx -dump http://{}/index.html \| wc -l ::: "${ARRAY[@]}" | awk '{s+=$1} END {print s}'
如果host:port在文件中:
cat host_port | parallel lynx -dump http://{}/index.html \| wc -l | awk '{s+=$1} END {print s}'
了解详情:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1