Como ler somente a última linha de um fluxo de entrada ao vivo em um loop de leitura while

0

Eu tenho um script bash muito simples que sincroniza dados com uma chave USB assim que novos arquivos aparecem. É mal escrito, mas funciona, mas quero minimizar o tempo de CPU, então usei sleep , mas como uso o inotifywait como um gatilho para sincronização, o script adiciona um segundo de suspensão a cada novo arquivo adicionado (e há muitos pequenos arquivos). Minha solução seria que read só lê a última linha de saída inotifywait, o que eu queria fazer canalizando-a para a cauda -1, mas parece que não funciona.

#!/bin/bash

watched_path=".wine/drive_c/Data"
rm -r "$HOME/$watched_path/"*
inotifywait -r -m "$HOME/$watched_path" --format "%e %w%f" -e create -e moved_to |
  while read action full_path; do
    sleep 1
    file=${full_path##*$watched_path}
    echo "'$file' appeared in directory '$watched_path' via '$action'"
    USB="USBKEY"

    # Wait for USB to be connected before syncing.
    until [ -e /media/$USER/$USB ]; do
      echo "Connect USB for sync."
      sleep 5
    done
    rsync -r "$HOME/$watched_path" /media/$USER/$USB
    echo "Sync complete."
  done

Eu sincronizo a pasta inteira, então tudo bem se eu perder uma linha de inotifywait, mas preciso que ela seja sincronizada após o último arquivo (e, portanto, a última linha) no momento da leitura. Isso significaria que, a partir do momento em que paro de enviar arquivos, o loop while será executado no máximo mais uma vez antes de ser interrompido novamente.

Como posso ler somente a linha mais recente da saída inotifywait? Se você tiver outras sugestões para evitar esse problema, tudo bem para mim, mas estou interessado na resposta, no entanto.

    
por Flabou 24.09.2018 / 14:05

1 resposta

0

Acho que você está pedindo por um cenário mais complexo. Você não descreveu como identificar o "último" arquivo a chegar, então este simplesmente expira após 5 segundos de inatividade do arquivo desde que pelo menos um arquivo foi transferido.

  1. Definir sinalizador = espera
  2. Em paralelo: sempre que um arquivo é notificado, defina flag = not_done
  3. Aguarde até sinalizar == not_done

  4. Iniciar ciclo

    • Aguarde a conexão do USB e inicie o processo de sincronização ( rsync )
    • Se algum novo arquivo for transferido, configure flag = not_done
    • Caso contrário
      • Se sinalizar == probably_done, defina sinalizador = definitivamente_conjunto. Caso contrário, configure sinalizador = probably_done
    • Se levarmos menos de cinco segundos, espere o tempo restante
  5. Fazer loop até sinalizar == definitivamente_done

Como precisamos de IPC entre o processo principal e o processo paralelo inotifywait , considero implementar o sinalizador como um arquivo, possivelmente até mesmo um conjunto de nomes de arquivos.

Tanto quanto eu posso dizer não é fácil identificar se rsync transferiu ou não novos arquivos . Pode ser necessário comparar o conteúdo do diretório de destino antes e depois.

    
por 24.09.2018 / 14:54