Usando expressões regulares e cauda para executar um comando

1

Igual a essa questão , no Linux tcsh Eu quero seguir um arquivo de log e quando eu corresponder a uma expressão regular, eu quero executar um comando arbitrário. Como posso fazer isso?

Ross Rogers
fonte

Respostas:

2

Na nota do pôster, um comentário nessa pergunta leva a uma postagem SO em desabilitando o buffer automático ao usar canos . A solução foi usar unbuffer (por Espero ), como em:

$ unbuffer tail -f foo | find-and-run "findwhat" "runwhat"

A resposta de wfaulk (mais a limpeza de ayrnieu) nos fornece o script find-and-run:

#!/usr/bin/perl
# run: find-and-run "regex-to-find" "commandtorun"
die "usage: $0 <regex> <exec-this> [exec-this-arg1 ...]\n"
   unless @ARGV >= 2;

my ($re, @run) = @ARGV; 

while (<>) {
        last if /$re/;
}
exec { $run[0] } @run;

Nota 1: no Debian lenny, você precisará instalar o pacote "expect-dev"; unbuffer é instalado como "expect_unbuffer".

Nota 2: isto é completamente não testado e completamente um pouco ingênuo. por segurança, não use isso. Se você usar isso, provavelmente desejará citar o seu regex para evitar a substituição / expansão do shell.

Nota 3: muito obrigado ao ayrnieu pela conclusão e limpeza do script.

quack quixote
fonte
1
die "uso: regex exec-this [arg1 ...] \ n" a menos que @ARGV & gt; = 2; meu ($ re, @run) = @ARGV; ... por último, se / $ re /; ... exec {$ run [0]} @run
ayrnieu
exec / system não é tão importante, mas $ 1 $ 2 definitivamente falhará, e uso: é apenas uma boa idéia.
ayrnieu
1
melhor: "uso: $ 0 & lt; regex & gt; & lt; exec-this & gt; [& lt; arg1 & gt; ... & lt; argn & gt;] \ n"
ayrnieu
3

Isso parece adequado para um script perl curto:

#!/usr/bin/perl

while (<>) {
        last if /regex/;
}
system("ls");

Se você deseja fornecer um padrão e um comando com argumentos sinalizados, consulte a documentação em perldoc Getopt::Std.

wfaulk
fonte
1
Eu realmente queria "& lt; & gt; até / regex /;" para trabalhar, mas não consegui fazer isso acontecer.
wfaulk
1
perl -Mwarnings -e 'escalar & lt; & gt; até / a / '- anote o aviso.
ayrnieu
1

No meu caso (no RHEL, eu queria tail -n 0 -f file | grep -m 1 pattern para terminar imediatamente quando ocorre um padrão no arquivo crescente), uso simples do unbuffer O utilitário do pacote Esperar não resolveu o problema por algum motivo.

Mas com base em um post no blog ( http://www.smop.co.uk/blog/index.php/2006/06/26/tail-f-and-awk/ ) Descobri que redirecionar a entrada da cauda lançada em um subshell fez o truque:

grep -m 1 pattern <(tail -n 0 -f file)

Isso não era tão simples, no entanto. Enquanto trabalhava em um shell interativo, o mesmo comando, quando executado remotamente usando o SSH, ainda congelava como de costume:

ssh login@hostname 'grep -m 1 pattern <(tail -n 0 -f file)'

Eu descobri que, neste caso, um deve unbuffer saída da cauda usando o unbuffer utilitário da Expect:

ssh login@hostname 'grep -m 1 pattern <(unbuffer -p tail -n 0 -f file)'

este Não deve ser usado em um shell interativo - o unbuffer causará ioctl(raw): I/O error!

Então, o conselho para você é que, se as soluções propostas não funcionarem, tente lançar tail -f em um subshell e se você quiser fazer isso em um script ou em um shell não interativo, usando unbuffer ou unbuffer -p pode ser necessário.

BTW, consulte este artigo para uma explicação detalhada do problema de buffer de saída: http://www.pixelbeat.org/programming/stdio_buffering/

Aleksander Adamowski
fonte
0

Uma abordagem diferente é usar um programa como amostra . O Swatch é construído para fazer exatamente o que você está falando, além de uma dúzia de outras coisas.

skarface
fonte