ディスクに保存したくない大量のデータを生成するアプリケーションがあります。アプリケーションは、ほとんどの場合、使用したくないデータを出力しますが、個別のファイルに分割する必要がある一連の有用な情報を出力します。たとえば、次の出力があるとします。
JUNK
JUNK
JUNK
JUNK
A 1
JUNK
B 5
C 1
JUNK
次のようにアプリケーションを3回実行できます。
./app | grep A > A.out
./app | grep B > B.out
./app | grep C > C.out
これは私が欲しいものを手に入れますが、時間がかかりすぎます。また、すべての出力を1つのファイルにダンプし、それを解析したくありません。
上記の3つの操作を組み合わせて、アプリケーションを1回実行するだけで3つの個別の出力ファイルを取得できるようにする方法はありますか?
Tシャツをお持ちの場合
./app | tee >(grep A > A.out) >(grep B > B.out) >(grep C > C.out) > /dev/null
(から ここ )
( プロセス置換について )
awk
を使用できます
./app | awk '/A/{ print > "A.out"}; /B/{ print > "B.out"}; /C/{ print > "C.out"}'
シェルの パターンマッチング機能 を使用することもできます。
./app | while read line; do
[[ "$line" =~ A ]] && echo $line >> A.out;
[[ "$line" =~ B ]] && echo $line >> B.out;
[[ "$line" =~ C ]] && echo $line >> C.out;
done
あるいは:
./app | while read line; do for foo in A B C; do
[[ "$line" =~ "$foo" ]] && echo $line >> "$foo".out;
done; done
-
で始まるバックスラッシュと行を処理できるより安全な方法:
./app | while IFS= read -r line; do for foo in A B C; do
[[ "$line" =~ "$foo" ]] && printf -- "$line\n" >> "$foo".out;
done; done
@StephaneChazelasがコメントで指摘しているように、これはあまり効率的ではありません。最善の解決策はおそらく @AurélienOoms ' です。
複数のコアがあり、プロセスを並列にしたい場合は、以下を実行できます。
parallel -j 3 -- './app | grep A > A.out' './app | grep B > B.out' './app | grep C > C.out'
これにより、並列コアで3つのプロセスが生成されます。コンソールまたはマスターファイルへの出力が必要な場合は、出力を混合するよりも、特定の順序で出力を維持できるという利点があります。
Ole Tangeのgnuユーティリティparallelは、ほとんどのリポジトリからparallelまたはという名前で入手できます。moreutils 。ソースは Savannah.gnu.org から取得できます。また、紹介用のビデオは here です。
補遺
Parallelの最新バージョン(ディストリビューションリポジトリのバージョンとは限りません)を使用すると、よりエレガントな構成を使用できます。
./app | parallel -j3 -k --pipe 'grep {1} >> {1}.log' ::: 'A' 'B' 'C'
これは、1つの./appと3つの並列grepプロセスを別々のコアまたはスレッドで実行した結果を実現します(並列自体によって決定されるように、-j3もオプションであると見なされますが、この例では説明のために提供されています)。
新しいバージョンのparallelは、次のようにして取得できます。
wget http://ftpmirror.gnu.org/parallel/parallel-20131022.tar.bz2
次に、通常の解凍、cd to parallel- {date}、。/ configure && make、Sudo make install。これにより、Parallel、Man Page Parallel、Man Page Parallel_tutorialがインストールされます。
これはPerlの1つです:
./app | Perl -ne 'BEGIN {open(FDA, ">A.out") and
open(FDB, ">B.out") and
open(FDC, ">C.out") or die("Cannot open files: $!\n")}
print FDA $_ if /A/; print FDB $_ if /B/; print FDC $_ if /C/'
sed -ne/A/w\ A.out -e/B/w\ B.out -e/C/p <in >C.out
... if<in
は読み取り可能です。3つの出力ファイルはすべて、何かが書き込まれる前に切り捨てられます。