Tubulação com Moreutils st


9

Eu tenho um fluxo de entrada em uma porta serial, com novas linhas aparecendo cerca de uma vez por segundo

wren@Raven:~$ cat /dev/ttyUSB0

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

A_Sensor1,B_22.00,C_50.00

Quero retirar as linhas em branco e marcar o restante do tempo.

O sed selecionará as linhas em branco e adicionará um carimbo de data / hora, mas não posso fazer a atualização do carimbo de data / hora, apenas informa a hora em que foi chamada:

wren@Raven:~$ cat /dev/ttyUSB0 | sed -e '/^$/d' -e "s/$/`date +\,%F\,%T`/"
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
A_Sensor1,B_22.00,C_50.00,2014-05-14,09:44:42
^C

Eu encontrei o ts, parte do Moreutils, e posso entrar nele para obter um carimbo de data / hora de atualização.

wren@Raven:~$ cat /dev/ttyUSB0 |  ts
May 14 09:49:26 A_Sensor1,B_22.00,C_50.00
May 14 09:49:26
May 14 09:49:27 A_Sensor1,B_22.00,C_50.00
^C

No entanto, não consigo combinar ts com sed.

Isso, que parece que deve fazer o que eu quero, não produz saída alguma

wren@Raven:~$ cat /dev/ttyUSB0 | sed -e '/^$/d' | ts
^C
wren@Raven:~$

No entanto, reverter a ordem dos tubos produz uma saída, mas é claro que não tira as linhas que não estão mais em branco. Outras substituições funcionam bem, então eu sei que o tubo para sed está funcionando.

wren@Raven:~$ cat /dev/ttyUSB0 |  ts | sed -e '/^$/d'
May 14 10:07:25 A_Sensor1,B_22.00,C_50.00
May 14 10:07:25
May 14 10:07:26 A_Sensor1,B_22.00,C_50.00
May 14 10:07:26
^C

Então, eu estou um pouco confuso. Presumivelmente, posso fazer com que o sed remova as linhas indesejadas, mas o carimbo de data e hora antes da remoção deve ser a abordagem errada.

Gostaria de receber uma explicação e alguma ajuda.

Respostas:


9

Responder diretamente à pergunta, sedé um buffer e esse é o único problema.
Você pode corrigir isso dizendo para não armazenar em buffer com seu -u/ --unbufferedflag:

sed -u '/^$/d' /dev/ttyUSB0 | ts

Com um equipamento de teste (mas você precisará executá-lo como prova):

$ (echo -e 'banana\n\n'; sleep 2; echo 'cheese') | sed -u '/^$/d' | ts
May 14 11:26:05 banana
May 14 11:26:07 cheese

Você pode encontrar situações semelhantes com outros editores de fluxo. Aparentemente, todos querem se proteger um pouco. Todos eles têm soluções alternativas. Aqui estão alguns comandos que eu testei:

... | mawk -W interactive '/./' | ts
... | gawk '/./ { print $0; fflush(); }' | ts
... | grep --line-buffered '.' | ts
... | perl -n -e 'print if /./' | ts

Outra idéia é apenas deixar gawklidar com isso. Ele pode filtrar linhas não vazias e imprimir a data para você (graças ao Kieron da SO ):

awk '/./ { print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }' /dev/ttyUSB0

Isso é liberado logo após a entrada das linhas. gawkÉ especialmente útil aqui se você quiser fazer outras coisas ... Se você quiser verificar se a quarta coluna da saída (pré- ts) corresponde a um regex, é possível (por exemplo $4~/\d{4}/). O Awk (e suas variantes) são muito flexíveis para o processamento de fluxo.

Outro equipamento de teste:

$ gawk '/./ { print strftime("%Y-%m-%d %H:%M:%S"), $0; fflush(); }' <(
      echo -e 'banana\n\n';
      sleep 2;
      echo 'cheese'
  )
2014-05-14 11:13:59 banana
2014-05-14 11:14:01 cheese

11
+1 para sed -u. É um problema de buffer de bloco vs. buffer de linha.
JFS

@Oli sed -u também funciona perfeitamente quando canalizado para ts, então eu vou ler sobre buffering. Não estou mais perplexo, muito obrigado.
perplexo

O awk é particularmente adequado para coisas como essa. O código awk é geralmente muito menos denso e muito mais legível que o sed, e você pode inserir quantas instruções de impressão desejar para exibir resultados parciais durante a depuração. Você pode colocar um programa awk inteiro em um documento here para evitar o uso de um arquivo separado e, se você colocar aspas na string terminadora do documento here, o bash ignorará todos os tokens incorporados que normalmente tentaria interpretar.
21314 Joe

0

bash pode lidar com isso em um while readloop

(echo -e 'banana\n\n'; sleep 2; echo 'cheese') | 
while IFS= read -r line; do 
    [[ $line ]] && echo "$(date "+%F %T") line"
done
2014-05-14 06:34:06 banana
2014-05-14 06:34:08 cheese

Você pode remover linhas apenas com espaços em branco com uma expansão de parâmetro complicada: remova todos os espaços em branco iniciais e veja se a linha está vazia:

shopt -s extglob

(echo -e '  banana\n\t\n'; sleep 2; echo 'cheese') |
while IFS= read -r line; do
    [[ "${line/#+([[:blank:]])/}" ]] && echo "$(date "+%F %T") $line"
done

Eu tentei uma variedade de abordagens como essa, nenhuma delas funcionou. Também não consigo fazer seu código funcionar. Usar echo ou cat para enviar / dev / ttyUSB0 para o loop while apenas resulta em uma única linha de saída: 2014-05-14 12:23:32 line
perplexed

Tenho certeza de que há uma maneira melhor, mas tente em tail -f /dev/ttyUSB0vez de gato ou eco. Ele continuará funcionando. Eu não sabia como testar isso no meu sistema.
21314 Joe

tail -f / dev / ttyUSB0 não fornece saída, com ou sem o loop while. tvm pelos seus comentários.
perplexo
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.