有没有办法并行化 bash for 循环?
Is there a way to parallelize a bash for loop?
我有一个简单的脚本,可以从一系列硬盘驱动器中提取 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 循环中,以便 fork 能够访问它。但是,如果脚本 运行 足够长以滚动到新的一分钟(或两分钟),然后脚本变成顺序的带日期戳的片段而不是一个连续的文件,这会导致问题。
这样的东西行不通吗? (未测试)
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
像这样使用 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
按顺序输出。如果你想 运行 添加 -j 8
,比如,一次 8 个,否则它会一次每个核心一个。或者 -j 16
如果你想 运行 一次全部...
parallel -j 16 -k 'smartctl ....
当然,如果你在bash
,你也可以这样做:
parallel -j 16 -k 'smartctl -a /dev/{}' ::: {a..o} > path/to/output
我有一个简单的脚本,可以从一系列硬盘驱动器中提取 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 循环中,以便 fork 能够访问它。但是,如果脚本 运行 足够长以滚动到新的一分钟(或两分钟),然后脚本变成顺序的带日期戳的片段而不是一个连续的文件,这会导致问题。
这样的东西行不通吗? (未测试)
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
像这样使用 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
按顺序输出。如果你想 运行 添加 -j 8
,比如,一次 8 个,否则它会一次每个核心一个。或者 -j 16
如果你想 运行 一次全部...
parallel -j 16 -k 'smartctl ....
当然,如果你在bash
,你也可以这样做:
parallel -j 16 -k 'smartctl -a /dev/{}' ::: {a..o} > path/to/output