Combine vários comandos unix em uma saída


9

Preciso pesquisar em nossos logs de email um endereço de email específico. Mantemos um arquivo atual chamado maillog , além de uma semana de arquivos .bz2 na mesma pasta. Atualmente, estou executando os seguintes comandos para procurar o arquivo:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

Existe uma maneira de combinar os comandos grepe bzgrepem uma única saída? Dessa forma, eu poderia canalizar os resultados combinados para um único email ou um único arquivo.

Respostas:


24

Outra maneira é

{ grep ...; bzgrep ...;} >file

&&tem a dificuldade de que o bzgrepnão seria executado se o grepfalhasse.

Observe o espaço obrigatório após a chave de abertura e o ponto e vírgula após o último comando. Como alternativa, você pode usar a sintaxe do subshell (parênteses em vez de chaves), que não é tão exigente:

(grep ...; bzgrep ...) >file

+1 para obter a melhor abordagem de shell de uso geral para esse problema. O agrupamento de shell é um recurso geralmente subutilizado.
Phil Hollenback

2
Você não quer dizer em ()vez de {}?
Ehtesh Choudhury

No arch linux, isso funcionou com, ()mas não {}, de qualquer maneira +1, pois é disso que eu precisava!
31715 Chris Magnuson

11

O bzgrep assume automaticamente o grep normal se um arquivo não estiver compactado com bzip. Portanto, o seguinte deve ser suficiente:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

Ah, claro, aqui está minha solução obrigatória GNU Parallel também:

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

o que pode ser muito mais rápido se você estiver verificando muitos arquivos.


2

Aqui está outra maneira de fazer isso (supondo que você esteja executando o bash, o que provavelmente é):

cat <(bzgrep ...) <(grep ...)

Aqui, o bash alimenta de maneira transparente a saída dos comandos bzgrep e grep no gato como se fossem arquivos (e meio que estão sob o capô, detalhes em url na parte inferior).

No seu caso particular, eu recomendaria a solução de Phil, mas o acima é um bom truque para manter em sua bolsa.

Se você estiver interessado, pode ler mais aqui: http://www.tldp.org/LDP/abs/html/process-sub.html


Ah, sim, a resposta canônica para 'como você difere a saída de dois processos'. Um bom truque para saber.
Phil Hollenback

1

No momento em que escrevi isso, a sintaxe da resposta aceita estava errada para a maioria, senão todas, as conchas derivadas de Bourne, inclusive bash. Sugeri uma edição na parte superior e aceitei a resposta para corrigir isso, mas também estava inclinado a adicionar todas essas outras informações, e isso teria sido mais uma reescrita do que uma edição.

Você pode usar comandos compostos:

{ grep ...; bzgrep ...; } >file

..ou subcascas (observe os parênteses em vez de chaves):

(grep ...; bzgrep ...) >file

..para agrupar os comandos. A maneira do subshell possui uma sintaxe melhor (mais tolerante à falta de espaço em branco e permite que você omita o último ponto e vírgula), mas cria um novo processo ou "finge" executando os comandos em um ambiente limpo. Ambos têm vantagens dependendo do que você deseja fazer, o que não importa aqui, mas vale a pena procurar se você quiser mais proficiência com o shell.

Nota: Você também pode usar o pipelining com esses truques, para fazer algo assim:

{ grep ...; bzgrep ...; } | less

PS se você não se preocupam com a ordem das partidas em sua produção combinada, você pode usar um único &entre os dois comandos, assim: { grep ... & bzgrep ...; }. Em seguida, os dois comandos são executados simultaneamente: o grepé lançado e o shell o coloca em segundo plano; então, o shell executa o bzgrep. (Mas há uma pequena ressalva sobre isso, com a explicação que envolve o redirecionamento de arquivos e o buffer de fluxo de arquivos, potencialmente fazendo com que uma parte muito pequena das linhas no arquivo de saída seja dividida / mutilada: se você verá isso, isso dependerá de como grep, bzgrep, e as libc stdio.hfunções são implementadas. Na maioria das implementações, acredito que canalizar o comando antes de redirecionar para um arquivo evitará o problema; portanto, você pode fazer isso { foo & bar; } | cat - >filecomo uma solução alternativa.)


0

Você pode amarrar os comandos com &&, o que permitirá executar cada comando.

você também pode adicionar >> textfile.txt ao final de cada comando e fazer com que a saída atinja um arquivo e envie-o por correio.


2
Como o geekosaur mencionado, && não deve ser usado aqui porque o valor de retorno do grep depende se ele encontrou algo ou não. Se você o fizesse grep ... && bzgrep ..., se o grep não tivesse acertos, ele retornaria a falha e o comando pararia. >>é uma boa idéia, porém, ao contrário >, ele adiciona saída ao final de um arquivo existente.
DerfK 8/03/11

certo, eu tinha esquecido a condição de saída, impedindo o segundo comando.
Mike
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.