Pergunta

Eu estou escrevendo scripts shell onde bastante regularidade alguma coisa está escrito para um arquivo, depois que um aplicativo é executado que lê esse arquivo. Acho que através da nossa empresa os difere de latência de rede muito, portanto, um sleep 2 simples, por exemplo, não será suficiente robusta.

Eu tentei escrever um (configurável) loop de tempo limite como esta:

waitLoop()
{
   local timeout=$1
   local test="$2"

   if ! $test
   then
      local counter=0
      while ! $test && [ $counter -lt $timeout ]
      do
         sleep 1
         ((counter++))
      done

      if ! $test
      then
         exit 1
      fi
   fi
}

Isso funciona para test="[ -e $somefilename ]". No entanto, testando a existência não é o suficiente, eu às vezes é preciso testar se uma determinada cadeia foi gravada no arquivo. eu tentei test="grep -sq \"^sometext$\" $somefilename", mas isso não funcionou. Alguém pode me dizer por quê?

Existem outras, menos detalhado opções para realizar tal teste?

Foi útil?

Solução

Você pode definir seu variável de teste desta maneira:

test=$(grep -sq "^sometext$" $somefilename)

A razão seu grep não está funcionando é que as aspas são realmente difíceis de passar argumentos. Você vai precisar usar eval:

if ! eval $test

Outras dicas

Eu diria que o maneira de verificar se há uma seqüência em um arquivo de texto é grep.

Qual é o seu problema exato com ele?

Além disso, você pode ajustar seus NFS parâmetros de montagem, para se livrar do problema de raiz. A sincronização também pode ajudar. Veja docs NFS.

Se você está querendo usar waitLoop em um "se", você pode querer mudar a "saída" para um "retorno", para que o resto do script pode lidar com a situação de erro (não há nem mesmo uma mensagem para o usuário sobre o que falhou antes de as matrizes de script não).

A outra questão é o uso de "$ test" para manter um meio de comando que não recebem expansão shell quando realmente executar, apenas avaliando. Então, se você diz test = "grep \" foo \ "\ 'bar baz \'", em vez de olhar para o três letras foo string no arquivo com os sete baz nome do personagem bar, ele vai olhar para a cadeia de cinco carvão "foo" no arquivo de nove char "bar baz".

Então você pode decidir que não precisa a magia shell, e teste de set = 'grep -sq ^ sometext $ somefilename', ou você pode obter o shell para lidar com a citar explicitamente com algo como:

if /bin/sh -c "$test"
then
   ...

Tente usar o tempo de modificação do arquivo para detectar quando é escrito sem abri-lo. Algo como

old_mtime=`stat --format="%Z" file`
# Write to file.
new_mtime=$old_mtime
while [[ "$old_mtime" -eq "$new_mtime" ]]; do 
  sleep 2;
  new_mtime=`stat --format="%Z" file`
done

Este não vai funcionar, no entanto, se vários processos tentar acessar o arquivo ao mesmo tempo.

Eu só tinha exatamente o mesmo problema. Eu usei uma abordagem semelhante para o tempo limite de espera que você incluir na sua OP; no entanto, eu também incluiu uma verificação de tamanho do ficheiro. Eu redefinir minha temporizador tempo limite se o arquivo tinha aumentado de tamanho desde a última foi marcada. Os arquivos que eu estou escrevendo pode ser um pouco show, assim que tomar um tempo para escrever através NFS.

Este pode ser um exagero para o seu caso particular, mas eu também tinha o meu processo de escrita calcular um hash do arquivo depois que ele foi feito por escrito. Eu costumava md5, mas algo como crc32 iria funcionar, também. Esse hash foi transmitido a partir do escritor para os (vários) leitores, eo leitor espera até que a) o tamanho do arquivo pára aumentar e b) o (recém computadorizada) hash do arquivo coincide com o hash enviado pelo escritor.

Nós temos um problema semelhante, mas por razões diferentes. Estamos lendo arquivo s, que é enviado para um servidor de SFTP. A máquina executando o script não é o servidor SFTP.

O que tenho feito é configurá-lo no cron (embora um laço com um sono iria trabalhar muito) para fazer uma cksum do arquivo. Quando o velho cksum corresponde ao cksum atual (o arquivo não foi alterado para a quantidade de tempo determinado) sabemos que as gravações estão completos, e transferir o arquivo.

Apenas para ser seguro extra, nós nunca substituir um arquivo local antes de fazer uma cópia de segurança, e só transferir em tudo quando o arquivo remoto tem dois cksums consecutivo em que jogo, e que cksum não coincide com o arquivo local.

Se precisar de exemplos de código, estou certo de que posso desenterrá-los.

O escudo foi dividir o seu predicado em palavras. Pegue tudo com $@ como no código a seguir:

#! /bin/bash

waitFor()
{
  local tries=$1
  shift
  local predicate="$@"

  while [ $tries -ge 1 ]; do
    (( tries-- ))

    if $predicate >/dev/null 2>&1; then
      return
    else
      [ $tries -gt 0 ] && sleep 1
    fi
  done

  exit 1
}

pred='[ -e /etc/passwd ]'
waitFor 5 $pred
echo "$pred satisfied"

rm -f /tmp/baz
(sleep 2; echo blahblah >>/tmp/baz) &
(sleep 4; echo hasfoo   >>/tmp/baz) &

pred='grep ^hasfoo /tmp/baz'
waitFor 5 $pred
echo "$pred satisfied"

Output:

$ ./waitngo 
[ -e /etc/passwd ] satisfied
grep ^hasfoo /tmp/baz satisfied

Pena que o texto datilografado não é tão interessante quanto vê-lo em tempo real.

Ok ... isso é um pouco whacky ...

Se você tem controle sobre o arquivo: você pode ser capaz de criar um 'pipe nomeado' aqui. Então, (dependendo de como o programa funciona escrita) você pode monitorar o arquivo de forma sincronizada.

Na sua forma mais simples:

Criar o pipe nomeado:

mkfifo file.txt

Configurar o receptor sincronizado:

while :
do
    process.sh < file.txt
end

Criar um remetente de teste:

echo "Hello There" > file.txt

O 'process.sh' é onde a sua lógica é: isto irá bloquear até que o remetente tem escrito sua saída. Em teoria, o programa escritor não vai precisar modifiying ....

AVISO: se o receptor não está funcionando por algum motivo, você pode acabar bloqueando o remetente

Não tenho certeza que se adapta à sua exigência aqui, mas pode valer a pena olhar em.

ou para evitar sincronizado, try 'lsof'?

http://en.wikipedia.org/wiki/Lsof

Assumindo que você só quer ler a partir do arquivo quando nada mais está escrevendo para ele (ou seja, o processo de escrita tenha terminado?) - você pode verificar se nada mais tem identificador de arquivo para ele

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top