Domanda

Sto scrivendo script di shell in cui una certa regolarità un po 'di roba è scritto a un file, dopo di che viene eseguita un'applicazione che legge il file. Trovo che attraverso la nostra azienda la latenza di rete si differenzia notevolmente, quindi un semplice sleep 2 ad esempio non sarà abbastanza robusto.

Ho provato a scrivere un (configurabile) ciclo di timeout in questo modo:

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
}

Questo funziona per test="[ -e $somefilename ]". Tuttavia, il test esistenza non è sufficiente, a volte bisogno di verificare se una certa stringa è stato scritto nel file. Provai test="grep -sq \"^sometext$\" $somefilename", ma questo non ha funzionato. Qualcuno può dirmi perché?

Ci sono altre opzioni, meno dettagliati per eseguire una simile prova?

È stato utile?

Soluzione

È possibile impostare la variabile di test in questo modo:

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

Il motivo per il vostro grep non funziona è che le quotazioni sono davvero difficili da passare in argomenti. Avrete bisogno di usare eval:

if ! eval $test

Altri suggerimenti

Direi che il modo per verificare la presenza di una stringa in un file di testo è grep.

Qual è il tuo problema esatto con esso?

Inoltre si potrebbe regolare la NFS parametri, per sbarazzarsi del problema alla radice. Una sincronizzazione potrebbe anche aiutare. Vedere documentazione NFS.

Se hai intenzione di utilizzare waitLoop in un "se", si potrebbe desiderare di cambiare il "uscita" per un "ritorno", in modo che il resto dello script in grado di gestire la situazione di errore (non c'è anche un messaggio a l'utente su ciò che non è riuscito prima che lo script muore in altro modo).

L'altro problema è l'utilizzo di "$ test" per contenere un comando significa che non si ottiene l'espansione shell quando in realtà l'esecuzione, basta valutare. Quindi, se dici test = "grep \" foo \ "\ 'bar baz \'", piuttosto che cercare la stringa di tre lettere pippo nel file con il nome di sette personaggio bar baz, sarà cercare la stringa char cinque "pippo" nel file nove char "bar baz".

Così si può decidere o non è necessario la magia della shell, e test di set = 'grep -sq ^ someText $ somefilename', o si può ottenere la shell per gestire il citando esplicitamente con qualcosa di simile:

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

Provare a utilizzare il tempo modifica del file per rilevare quando è scritto senza aprirlo. Qualcosa di simile

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

Questo non funziona, tuttavia, se più processi tentano di accedere al file allo stesso tempo.

Ho appena avuto lo stesso identico problema. Ho usato un approccio simile per il timeout di attesa di includere nel vostro OP; tuttavia, ho incluso anche un controllo del file-size. Ripristina il timer timeout se il file era aumentato in termini di dimensioni rispetto ad essa è stata verificata. I file che sto scrivendo può essere una qualche concerto, in modo da prendere un po 'di scrivere attraverso NFS.

Questo può essere eccessivo per il vostro caso particolare, ma ho anche avuto il mio processo di scrittura calcolare un hash del file dopo che è stato fatto per iscritto. Ho usato MD5, ma qualcosa di simile crc32 avrebbe funzionato, anche. Questo hash è stato trasmesso dallo scrittore alle (più) i lettori, e il lettore attende che a) la dimensione del file smette di aumentare e b) il (recente computerizzata) hash del file corrisponde l'hash inviato dallo scrittore.

Abbiamo un problema simile, ma per motivi diversi. Stiamo leggendo il file s, che viene inviato a un server SFTP. La macchina che esegue lo script non è il server SFTP.

Quello che ho fatto è impostato su in cron (anche se un ciclo con un sonno avrebbe funzionato troppo) per fare un cksum del file. Quando il vecchio cksum corrisponde al cksum corrente (il file non è cambiato per la quantità di tempo determinato) sappiamo che le operazioni di scrittura sono completi, e trasferire il file.

Giusto per essere più sicuro, non abbiamo mai sovrascrivere un file locale prima di fare una copia di backup, e solo il trasferimento a tutti quando il file remoto ha due cksums di fila che corrispondono, e che cksum non corrisponde al file locale.

Se avete bisogno di esempi di codice, sono sicuro che io possa scavare.

Il guscio spaccava la tua predicato in parole. Prendete il tutto con $@ come nel seguente codice:

#! /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

Peccato che il dattiloscritto non è così interessante come guardare in tempo reale.

Ok ... questo è un po 'sgargianti ...

Se si ha il controllo del file: si potrebbe essere in grado di creare un 'named pipe' qui. Quindi (a seconda di come il programma di scrittura funziona) è possibile monitorare il file in modo sincronizzato.

Nel caso più semplice:

Crea la named pipe:

mkfifo file.txt

Imposta il ricevitore sincronizzati:

while :
do
    process.sh < file.txt
end

Crea un mittente di prova:

echo "Hello There" > file.txt

Il 'process.sh' è dove la logica va: questo bloccherà fino a quando il mittente ha scritto la sua uscita. In teoria il programma scrittore non avrà bisogno modifiying ....

ATTENZIONE: se il ricevitore non è in esecuzione, per qualche motivo, si può finire per bloccare il mittente

Non sono sicuro che si adatta alle vostre esigenze qui, ma forse vale la pena di essere esaminata.

o per evitare sincronizzato, prova a 'lsof'?

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

Supponendo che si desideri solo leggere dal file quando nient'altro sta scrivendo ad esso (cioè, il processo di scrittura è finito?) - si potrebbe verificare se non altro ha handle di file ad esso

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top