“Observe” a saída de um comando até que uma determinada sequência seja observada e saia

29

Estou procurando uma maneira de assistir programaticamente a saída de um comando até que uma determinada string seja observada e depois saia. Isso é muito semelhante a essa pergunta, mas, em vez de ajustar um arquivo, quero 'ajustar' um comando.

Algo como:

assistir -n1 my_cmd | grep -m 1 "String que estou procurando"

(Mas isso não funciona para mim.)

UPDATE: Preciso esclarecer que 'my_cmd' não gera texto continuamente, mas precisa ser chamado repetidamente até que a string seja encontrada (e foi por isso que pensei no comando 'watch'). Nesse aspecto, 'my_cmd' é como muitos outros comandos unix, como: ps, ls, lsof, last, etc.

gdw2
fonte
Eu teria pensado que era possível tail -fuma saída de programa tão bem quanto um arquivo ... Estou errado?
Joanis
@Joanis. Você está certo, mas no meu caso 'my_cmd' não continuamente produzir saída e deve ser repetidamente chamado (muito parecido com a maioria dos comandos: ps, ls, lsof, etc.)
gdw2

Respostas:

41

Use um loop:

until my_cmd | grep -m 1 "String Im Looking For"; do : ; done

Em vez de :, você pode usar sleep 1(ou 0.2) para facilitar a CPU.

O loop é executado até que o grep encontre a string na saída do comando. -m 1significa "uma correspondência é suficiente", ou seja, o grep para de procurar depois de encontrar a primeira correspondência.

Você também pode usar o grep -qque também fecha após encontrar a primeira correspondência, mas sem imprimir a linha correspondente.

choroba
fonte
uma explicação desse comando seria apreciada.
Mark W
@ MarkW: Atualizado.
choroba
alguém mencionou grep -qque é outra opção. O grep é encerrado após encontrar a string.
Dom
observe que esse comando executará repetidamente o comando em questão, o que pode ou não ser desejável.
adrien 12/06
1
@A__: É desejável, conforme declarado no OP em "Atualização".
choroba 12/06
11
watch -e "! my_cmd | grep -m 1 \"String Im Looking For\""
  • ! nega o código de saída do pipeline de comandos
  • grep -m 1 sai quando a string é encontrada
  • watch -e retorna se algum erro ocorreu

Mas isso pode ser melhorado para realmente exibir a linha correspondente, que é jogada fora até agora.

matemática
fonte
Obrigado pela explicação detalhada, mas não funciona para mim. Meu watchcomando (CentOS) não tem a -ebandeira (o que realmente não deveria importar). Mais importante, porém, quando a string é encontrada, o relógio continua a funcionar e não sai. Parece que quando grep -msai, sai apenas mata my_cmd, mas não watch.
Gdw2
Não, isso importa !, o sinalizador "-e" serve para deixar o relógio quando o comando tem um código de erro diferente de 0. Como o relógio não está presente, está prestes a continuar na sua plataforma. De qualquer forma, é bom saber que na minha instalação do Ubuntu 11.10 está tudo bem. Às vezes, também tenho problemas com o Mac OSX em relação a ferramentas de linha de comando muito desatualizadas e estou usando portas mac até agora para obter um software mais atual.
math
Isso interrompe se o padrão for encontrado, mas não mostrará nenhuma saída, até que isso aconteça
Mark
Você pode empregar teepara isso, mas isto introduz uma nova linha enganosa, eu não sei como contornar agora:watch -n1 -e "! date | tee /dev/tty | grep --color -m 1 \"17\""
matemática
Sim, isso não funcionou para mim. watchobedientemente pára de observar quando a string é encontrada, mas na verdade não sai até você pressionar uma tecla. Tão perto.
Mlissner
8

Para aqueles que têm um programa que está gravando continuamente no stdout, tudo o que você precisa fazer é canalizá-lo para grep com a opção 'correspondência única'. Quando o grep encontrar a string correspondente, ele sairá, o que fecha o stdout no processo que está sendo canalizado para o grep. Esse evento naturalmente deve fazer com que o programa saia normalmente desde que o processo seja gravado novamente .

O que acontecerá é que o processo receberá um SIGPIPE quando tentar gravar no stdout fechado após a saída do grep. Aqui está um exemplo com o ping, que seria executado indefinidamente:

$ ping superuser.com | grep -m 1 "icmp_seq"

Este comando corresponderá ao primeiro 'pong' bem-sucedido e, em seguida, sairá da próxima vez que pingtentar gravar no stdout.


Contudo,

Nem sempre é garantido que o processo seja gravado no stdout novamente e, portanto, pode não causar o aumento de um SIGPIPE (por exemplo, isso pode acontecer ao seguir um arquivo de log). A melhor solução que consegui encontrar para esse cenário envolve a gravação em um arquivo; comente se você acha que pode melhorar:

$ { tail -f log_file & echo $! > pid; } | { grep -m1 "find_me" && kill -9 $(cat pid) && rm pid; }

Quebrando isso:

  1. tail -f log_file & echo $! > pid- segue um arquivo, anexa o processo ao plano de fundo e salva o PID ( $!) em um arquivo. Tentei exportar o PID para uma variável, mas parece que há uma condição de corrida entre aqui e quando o PID é usado novamente.
  2. { ... ;}- agrupe esses comandos para que possamos canalizar a saída para grep, mantendo o contexto atual (ajuda ao salvar e reutilizar variáveis, mas não foi capaz de fazer essa parte funcionar)
  3. | - canalize o stdout do lado esquerdo para o stdin do lado direito
  4. grep -m1 "find_me" - encontre a string de destino
  5. && kill -9 $(cat pid)- force kill (SIGKILL) o tailprocesso após grep sair depois de encontrar a string correspondente
  6. && rm pid - remova o arquivo que criamos
Blake Regalia
fonte
0
my_cmd | tail +1f | sed '/String Im Looking For/q'

Se tailnão suportar a +1fsintaxe, tente tail -f -n +1. (Ele -n +1diz para começar do início; tail -fpor padrão, começa com as últimas 10 linhas de saída.)

Keith Thompson
fonte
Por favor, veja minha atualização para a pergunta.
Gdw2
0

Anexe o resultado de suas chamadas de programa a um arquivo. Então tail -fesse arquivo. Dessa forma, deve funcionar ... espero.

Ao reiniciar a chamada para esse programa, você terá que apagar o arquivo ou anexá-lo a alguma coisa, para que não corresponda novamente imediatamente ao que estava procurando.

Joanis
fonte