piped command depois do grep não funcionar

1

Eu quero monitorar um arquivo. Então, eu segui um arquivo usando o comando abaixo, para executar um script por linha.

tail -3f logfile.log | grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh

Mas parece que o script não está sendo executado. Eu observei que grep não está dando nenhuma entrada para o próximo pipe.

Quando tentei,

tail -3f logfile.log | grep "action.*add"

funcionou. Mas quando for dado o próximo filtro como sed , grep , xargs etc. Ele não funcionou como o mostrado abaixo.

tail -3f /var/tmp/rabbitmq-tracing/logfile.log | grep "action.*add" | grep add 

Por favor me ajude a saber por que isso está acontecendo e como superar isso.

Editar 1: Basicamente, qualquer coisa como abaixo deveria funcionar e estava funcionando anteriormente. Confuso porque não está funcionando agora.

tail -f file.txt | grep something | grep something | grep something

EDIT 2: Linha de saída após o primeiro grep será uma string json como abaixo. E eu quero dar essa linha como entrada (entre aspas simples) para bash script.

{"twNotif": {"originator": "api", "chain": "test", "txId": "08640-0050568a5514", "version": "1.0", "msgType": "api", "twData": {"api": {"hostId": "007bdcc5", "user": "test", "cmdTxt": "100599"}}, "action": "add", "store": "test", "msgTime": 1467280648.971042}}
    
por AVJ 01.07.2016 / 13:16

3 respostas

1

use --line-buffered em grep

tail -3f logfile.log | grep --line-buffered "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh

do man grep:

--line-buffered Use line buffering on output. This can cause a performance penalty.

ou você pode usar stdbuf leia mais

stdbuf allows one to modify the buffering operations of the three standard I/O streams associated with a program. Synopsis:

use esta sintaxe:

... | stdbuf -oL grep ... | ...

seu exemplo:

tail -3f logfile.log | stdbuf -oL grep "action.*add" | sed -u -e "s/^/'/" -e "s/$/'/" | xargs -L 1 -P 5 bash testscript.sh
    
por 01.07.2016 / 14:00
1

Como outros já notaram, o buffer de linha de grep é a causa óbvia do seu problema.

No entanto, existem outros problemas com o que você está fazendo que não são tão óbvios.

Para começar, parece que você está usando sed para adicionar apóstrofos ao início e ao final de cada linha de saída para que você possa alimentá-lo em xargs . Isso nem é remotamente necessário - xargs tem -d opção que você pode usar para dizer que use novas linhas como delimitador: por exemplo, xargs -d'\n' -r (a opção -r serve para garantir que xargs não faça nada se não houver linhas de entrada)

Em segundo lugar, você está usando expressões regulares para analisar dados do json. Isso não é confiável, extremamente difícil ou mesmo impossível de se acertar com estruturas complexas / aninhadas, frágeis e propensas a quebrar na barra de um chapéu, exatamente pelas mesmas razões que usar regexps para analisar XML ou HTML não é confiável, extremamente difícil e frágil. Não analise XML ou HTML com expressões regulares . não funciona . O mesmo se aplica ao json .

Em vez disso, você deve usar algo como jq ou jsonpipe para extrair campos dos dados do json. Por exemplo:

jq -c 'select(.twNotif.action == "add")' file.txt | 
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

Se você quisesse enviar o valor do campo de ação para xargs (sem as aspas duplas), poderia fazer assim:

jq 'select(.twNotif.action == "add") | .twNotif.action' file.txt | 
  sed -e 's/"//g' | 
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

Usar jsonpipe e awk provavelmente seria mais fácil para um trabalho como esse:

jsonpipe < file.txt | 
  awk '$1 == "/twNotif/action" {gsub(/"/,""); print $2}' |
  xargs -d'\n' -r -L 1 -P 5 ./testscript.sh

(observe o redirecionamento aqui, ao contrário de jq , jsonpipe funciona apenas com stdin).

BTW, jsonpipe transforma dados json em um formato orientado a linha adequado para uso com ferramentas orientadas a linha como sed , grep , awk , etc. Por exemplo:

$ jsonpipe < file.txt
/   {}
/twNotif    {}
/twNotif/originator "api"
/twNotif/chain  "test"
/twNotif/txId   "08640-0050568a5514"
/twNotif/version    "1.0"
/twNotif/msgType    "api"
/twNotif/twData {}
/twNotif/twData/api {}
/twNotif/twData/api/hostId  "007bdcc5"
/twNotif/twData/api/user    "test"
/twNotif/twData/api/cmdTxt  "100599"
/twNotif/action "add"
/twNotif/store  "test"
/twNotif/msgTime    1467280648.971042

É mais fácil trabalhar com jq , especialmente se você não precisa de saída formatada em json.

Também é útil para listar a estrutura de e os campos / elementos em um arquivo json no formulário que pode ser facilmente usado com jq . por exemplo:

$ jsonpipe <file.txt | awk '{gsub(/\//,"."); print $1}'
.
.twNotif
.twNotif.originator
.twNotif.chain
.twNotif.txId
.twNotif.version
.twNotif.msgType
.twNotif.twData
.twNotif.twData.api
.twNotif.twData.api.hostId
.twNotif.twData.api.user
.twNotif.twData.api.cmdTxt
.twNotif.action
.twNotif.store
.twNotif.msgTime
    
por 03.07.2016 / 10:46
0

O problema que você provavelmente está vendo é "buffer de pipeline"; a saída de vários componentes do pipeline (no seu caso, o grep ) não são mais armazenados em buffer de linha, mas em buffer de bloco, e um buffer pode ser 4K ou mais O componente seguinte não vê os dados imediatamente. Ele irá vê-lo quando dados suficientes ocorrerem ...

A solução é um pouco dolorosa. Felizmente, o pacote expect vem com comamnd unbuffer , o que pode ajudar. man unbuffer para mais detalhes sobre como usar isso.

Funciona fazendo com que os componentes do pipeline pensem que estão falando com um terminal e, portanto, permaneçam no buffer de linha.

    
por 01.07.2016 / 13:28

Tags