有没有办法并行化bash for循环?

时间:2015-09-30 05:19:42

标签: bash for-loop parallel-processing

我有一个简单的脚本,它从一系列硬盘驱动器中提取SMART数据并将其写入带时间戳的日志文件,该文件稍后会被记录并解析相关数据。

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i >> /path/to/location/$filename
done 

由于这需要几秒钟才能运行,我想找到一种方法来并行化它。我试过添加'&'到循环中单行的末尾,然而这导致文本文件随着部分完成而不是顺序地以可读的方式被随意写入。有没有办法将它分成每个驱动器的单独进程,然后将输出管道传输回有序的文本文件?

另外,我假设设置文件名变量必须移动到for循环中,以便forks能够访问它。然而,这会导致一个问题,如果脚本运行的时间足够长,可以翻到新的一分钟(或两分钟),然后脚本会成为按日期戳记的片段,而不是一个连续的文件。

2 个答案:

答案 0 :(得分:2)

使用GNU Parallel这样:

parallel -k 'smartctl -a /dev/{}' ::: a b c d e f g h  i j k l m n o p > path/to/output

-k选项keeps按顺序输出。如果您想要一次运行8个,请添加-j 8,否则每个核心一次运行一个。或-j 16如果你想一次性运行它们......

parallel -j 16 -k 'smartctl ....

当然,如果你在bash,你也可以这样做:

parallel -j 16 -k 'smartctl -a /dev/{}' ::: {a..o} > path/to/output

答案 1 :(得分:1)

不会有这样的工作吗? (未经测试)

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i > /path/to/location/$filename.$i &
done
wait
cat /path/to/location/$filename.* > /path/to/location/$filename
编辑:看起来最后的猫很慢,那么这个版本怎么样?

filename="filename$( date '+%Y_%m_%d_%H%M' ).txt"
tmpdir="/dev/shm/tmp$( date '+%Y_%m_%d_%H%M' )"
mkdir $tmpdir
for i in {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}
do
smartctl -a /dev/sd$i > $tmpdir/$filename.$i &
done
wait
cat $tmpdir/$filename.* > /path/to/location/$filename
rm -rf $tmpdir