Se você tiver tee
./app | tee >(grep A > A.out) >(grep B > B.out) >(grep C > C.out) > /dev/null
(de aqui )
Eu tenho uma aplicação que irá produzir uma grande quantidade de dados que eu não quero armazenar no disco. A aplicação produz principalmente dados que eu não desejo usar, mas um conjunto de informações úteis que devem ser divididas em arquivos separados. Por exemplo, dada a seguinte saída:
JUNK
JUNK
JUNK
JUNK
A 1
JUNK
B 5
C 1
JUNK
Eu poderia executar o aplicativo três vezes da seguinte forma:
./app | grep A > A.out
./app | grep B > B.out
./app | grep C > C.out
Isso me daria o que eu quero, mas levaria muito tempo. Eu também não quero despejar todas as saídas para um único arquivo e analisá-lo.
Existe alguma maneira de combinar as três operações mostradas acima de tal forma que eu só precise executar o aplicativo uma vez e ainda obter três arquivos de saída separados?
Se você tiver tee
./app | tee >(grep A > A.out) >(grep B > B.out) >(grep C > C.out) > /dev/null
(de aqui )
Você pode usar awk
./app | awk '/A/{ print > "A.out"}; /B/{ print > "B.out"}; /C/{ print > "C.out"}'
Você também pode usar as habilidades de correspondência de padrões do seu shell :
./app | while read line; do
[[ "$line" =~ A ]] && echo $line >> A.out;
[[ "$line" =~ B ]] && echo $line >> B.out;
[[ "$line" =~ C ]] && echo $line >> C.out;
done
Ou até mesmo:
./app | while read line; do for foo in A B C; do
[[ "$line" =~ "$foo" ]] && echo $line >> "$foo".out;
done; done
Uma maneira mais segura de lidar com barras invertidas e linhas que começam com -
:
./app | while IFS= read -r line; do for foo in A B C; do
[[ "$line" =~ "$foo" ]] && printf -- "$line\n" >> "$foo".out;
done; done
Como aponta @StephaneChazelas nos comentários, isso não é muito eficiente. A melhor solução é provavelmente @ AurélienOoms '.
Se você tiver vários núcleos e quiser que os processos estejam em paralelo, faça o seguinte:
parallel -j 3 -- './app | grep A > A.out' './app | grep B > B.out' './app | grep C > C.out'
Isso gerará três processos em núcleos paralelos. Se você quiser que haja alguma saída para o console ou um arquivo mestre, ele terá a vantagem de manter a saída em alguma ordem, em vez de misturá-la.
O utilitário gnu paralelo do Ole Tange pode ser obtido a partir da maioria dos repos com o nome paralelo ou moreutils . A fonte pode ser obtida em Savannah.gnu.org . Além disso, um vídeo instrutivo introdutório é aqui .
Adendo
Usando a versão mais recente do paralela (não necessariamente a versão em seu repositório de distribuição), você pode usar a construção mais elegante:
./app | parallel -j3 -k --pipe 'grep {1} >> {1}.log' ::: 'A' 'B' 'C'
Que alcança o resultado da execução de um ./app e 3 processos grep paralelos em núcleos ou encadeamentos separados (conforme determinado pelo próprio paralelismo, também considere o -j3 como opcional, mas é fornecido neste exemplo para propósitos instrutivos) .
A versão mais recente do paralelo pode ser obtida fazendo:
wget http://ftpmirror.gnu.org/parallel/parallel-20131022.tar.bz2
Em seguida, o habitual descompactar, cd para parallel- {date}, ./configure & & make, sudo make install. Isso instalará o paralelismo, a página man paralela e a página man parallel_tutorial.
Aqui está uma em Perl:
./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
... se <in
for legível, todos os três arquivos serão truncados antes que algo seja escrito para eles.