Como [constantemente] lê a última linha de um arquivo?

0

Eu tenho o cliente filtrando dados de um fluxo MQTT ao vivo que grava os dados em um arquivo myfile.csv , aqui estão as últimas quatro linhas:

1426134425,m,NWRL,MSV,001,d,SVlts,139,1840343,26089,28529,15987
1426134444,m,NWRL,MSV,001,d,status,139,1859000,23911,-33.836465,151.051189
1426134834,m,gf,TMX6BP,075,d,SVlts,216,1243746,27209,27409,17106
1426134845,m,gf,TMX6BP,075,d,status,216,1254000,179583,-33.836465,151.051189

Este arquivo é constantemente atualizado. Portanto, a última linha do arquivo csv estaria constantemente mudando, mas ainda assim estaria no mesmo formato.

P: Como posso ler a última linha em que o 7º valor é 'status' e não 'SVlts' do arquivo myfile.csv com o bash? Uma vez lida como posso atribuir o 4º, 5º e 10º valor a 3 variáveis diferentes? Eu vou estar empurrando esses valores para atualizar uma tabela MySQL.

Assim, a saída pode ser algo como segue:

variable_1=TMX6BP
variable_2=075
variable_3=179583

Como mencionado, estas três variáveis serão enviadas / enviadas para atualizar uma tabela MySQL (que precisa dessas três variáveis para se atualizar) até que a próxima linha seja impressa no myfile.csv . E isso vai acontecer de novo e de novo.

    
por 3kstc 12.03.2015 / 06:10

3 respostas

1

Isso captura as informações desejadas da última linha de file :

$ IFS=, read -r a b c var_1 var_2 d e f h var_3 extra < <(tail -n1 file)
$ echo $var_1  $var_2  $var_3
TMX6BP 075 179583

Como funciona

  • IFS=,

    Isso define temporariamente o separador de campo para uma vírgula.

  • read -r a b c var_1 var_2 d e f h var_3 extra

    Isto lê os campos para as variáveis listadas. Você pode escolher qualquer nome que quiser.

    Acima, o primeiro campo é atribuído à variável do shell a , o segundo ao b , etc. Tudo o que sobrou depois que var_3 é atribuído à variável do shell extra .

  • < <(tail -n1 file)

    Isso fornece a última linha de file como entrada padrão para o comando read . O primeiro < é o símbolo da shell para redirecionamento. A construção <(...) é chamada de substituição de processo. O espaço entre o primeiro e o segundo < é essencial .

por 12.03.2015 / 06:42
1

Resposta curta:

   # tail -F: output appended data as the file grows
   #      Capital F to follow even if the file is reset to zero, recreated, etc.
   # awk -F, sets FS - Field Separator to a comma
   #   Inside awk: See if field 7 == "status" and print fields 4, 5 and 10
tail -F myfile.csv | awk -F, '$7 == "status" { print $4, $5, $10 }'

Você não está escrevendo como atualizará seu banco de dados, então escreverei algo que possa ajudá-lo a começar.

Também é meu entendimento que você NÃO editará o arquivo myfile.csv, mas usará as 3 variáveis mencionadas como entrada para um script / job de atualização. Verificação de erros, etc, eu vou deixar para você.

Primeiro, crie o script que atualiza seu banco de dados MySQL. Eu vou apenas zombar daqui.

#!/bin/bash
# update-MySQL-table.sh
    # redirecting stderr to stdout so awk will see it.
    # Not much use with "echo", but ...
echo $0 $1 $2 $3 2>&1

Depois, você tem outro script que lê e analisa seu arquivo CSV e inicia o script de atualização do banco de dados.

#!/bin/bash
# parse-my-CSV-file.sh
csvfile="myfile.csv"

tail -n0 -F $csvfile | \
    awk -F, '
        $7 == "status" {
            cmd=sprintf("./update-MySQL-table.sh %s %s %s",$4,$5,$10)
            cmd | getline output
            print output
    }'

Você inicia então o script parse e verá como as novas linhas adicionadas ao myfile.csv com "status" no 7º campo serão impressas no stdout.

    
por 12.03.2015 / 09:31
1

Eu faria algo como:

tail -n1 -f file | 
  perl -MDBI -F, -lane 'BEGIN{$d = DBI->connect(...)}
    if ($F[6] eq "status") {
      $d->do("INSERT INTO foo VALUES (?,?,?)", @F[3,4,9]);
    }'
    
por 12.03.2015 / 09:38