LoginSignup
38
40

More than 5 years have passed since last update.

コマンドを並列実行しつつエラーのあった実行のログを最後にまとめて出力するシェルスクリプト

Posted at

並列実行というと xargsGNU parallel を思い出しますが、「エラーのあった実行のログを最後にまとめて出力する」ということを考えるとどちらも不十分でした。(できるのであれば教えてほしい)

しかし、シェルには wait などの素敵な並列実行の仕組みが用意されているので、頑張って自分で実装してみました。

#!/bin/bash
#
# parallel.sh
# usage: echo 1 2 3 4 5 | parallel.sh my_script.sh
# 標準入力から受け取ったリストを引数として、引数で与えられたコマンドを実行する
# 成功したコマンドの結果を先に出力してから失敗したコマンドの結果を最後にまとめて出力する

list=$(cat)
tmpdir=$(mktemp -d)

for i in $list
do
  ($@ $i > $tmpdir/$i.log 2>&1; echo -n $? > $tmpdir/$i.status) &
done

wait

for i in $list
do
  [ $(cat $tmpdir/$i.status) -eq 0 ] && cat $tmpdir/$i.log
done

for i in $list
do
  [ $(cat $tmpdir/$i.status) -ne 0 ] && cat $tmpdir/$i.log && echo '*** error occurred!! ***'
done

code=0
for i in $list
do
  status=$(cat $tmpdir/$i.status)
  echo "status $status for command: $@ $i"
  [ $status -ne 0 ] && code=$(expr $code + 1)
done

rm -r $tmpdir
exit $code

http://qiita.com/geta6/items/199faca823e84026c10a ←この記事を読めば解説は不要です。要は、すべてのコマンドをバックグラウンドで実行し、出力を $tmpdir/$i.log に書いて、ステータスを $tmpdir/$i.status に書いていて、あとは一個一個それらを処理しているだけです。

実験

引数が3の倍数のときだけ失敗するこのようなスクリプトを用意し、

#!/bin/bash

if [ $(expr $1 % 3) -eq 0 ]; then
  echo $1
  exit 1
else
  echo $1
  exit 0
fi

echo 1 2 3 4 5 6 7 8 9 | ./parallel.sh ./cmd.sh のように実行すると、

1
2
4
5
7
8
3
*** error occurred!! ***
6
*** error occurred!! ***
9
*** error occurred!! ***
status 0 for command: ./cmd.sh 1
status 0 for command: ./cmd.sh 2
status 1 for command: ./cmd.sh 3
status 0 for command: ./cmd.sh 4
status 0 for command: ./cmd.sh 5
status 1 for command: ./cmd.sh 6
status 0 for command: ./cmd.sh 7
status 0 for command: ./cmd.sh 8
status 1 for command: ./cmd.sh 9

こうなるのがわかります。

38
40
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
40