Frage

Ich schreibe Shell-Skripte, wo ziemlich regelmäßig einige Sachen geschrieben in eine Datei, wonach eine Anwendung ausgeführt, dass diese Datei liest. Ich finde, dass die Netzwerklatenz unterscheidet sich erheblich von unserem Unternehmen, so dass eine einfache sleep 2 zum Beispiel nicht robust genug sein.

I versuchte, eine (konfigurierbar) Timeout-Schleife wie folgt zu schreiben:

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
}

Dies funktioniert für test="[ -e $somefilename ]". Allerdings Existenz Prüfung ist nicht genug, ich brauche manchmal zu testen, ob eine bestimmte Zeichenfolge in die Datei geschrieben wurde. Ich habe es versucht test="grep -sq \"^sometext$\" $somefilename", aber das hat nicht funktioniert. Kann mir jemand sagen, warum?

Gibt es andere, weniger ausführlich Optionen einen solchen Test durchführen?

War es hilfreich?

Lösung

Sie können Ihre Testvariable auf diese Weise festgelegt:

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

Der Grund Ihrer grep nicht funktioniert ist, dass Zitate sind wirklich schwer in Argumente zu übergeben. Sie müssen eval verwenden:

if ! eval $test

Andere Tipps

Ich würde sagen, die Art und Weise für eine Zeichenfolge in einer Textdatei zu überprüfen ist, grep.

Was ist Ihr genaues Problem mit ihm?

Auch könnte passen Sie Ihre NFS Parameter montieren, die Beseitigung der Wurzel Problem zu bekommen. Ein Sync könnte auch helfen. Siehe NFS-Dokumentation.

Wenn Sie wollen waitLoop verwenden, in einer „if“, können Sie die „Exit“, um vielleicht ändern wollen eine „Rückkehr“, so dass der Rest des Skripts die Fehlersituation umgehen kann (es gibt nicht einmal eine Nachricht an der Benutzer über das, was fehlgeschlagen, bevor das Skript stirbt sonst).

Das andere Problem „$ test“ wird mit einem Befehl zu halten, bedeutet, dass Sie keine Shell-Erweiterung erhalten, wenn tatsächlich ausgeführt wird, nur zu bewerten. Also, wenn Sie Test sagen = „grep \“ foo \ „\‚bar baz \‘“, statt in der Datei für den Drei-Buchstaben-String foo suchen mit dem sieben Charakternamen bar baz, wird es aussehen für die fünf char string "foo" in der neun char Datei "bar baz".

So können Sie entweder entscheiden Sie die Shell Magie nicht benötigen, und stellen Sie Test = ‚grep -SQ ^ sometext $ somefilename‘, oder Sie können die Shell die zitierte explizit mit so etwas wie zu handhaben bekommen:

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

Versuchen Sie die Datei-Änderungszeit mit zu erfassen, wenn es ohne Öffnen geschrieben steht. So etwas wie

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

Das wird nicht funktionieren jedoch, wenn mehr Prozesse versuchen, die Datei in der gleichen Zeit zuzugreifen.

Ich hatte gerade genau das gleiche Problem. Ich benutzte einen ähnlichen Ansatz für die Timeout-Warte, die Sie in Ihrem OP umfassen; aber ich auch eine Datei-Größe zu überprüfen. Ich zurückgesetzt meinen Timeout-Timer, wenn die Datei seit dem letzten in der Größe zugenommen hat geprüft wurde. Die Dateien schreibe ich kann ein paar Konzerte sind, so dass sie eine Weile dauern, über NFS zu schreiben.

Dies kann Overkill für Ihren speziellen Fall sein, aber ich hatte auch meine Schreibprozess einen Hash der Datei berechnen, nachdem er das Schreiben war getan. Ich benutzte md5, aber so etwas wie crc32 funktionieren würde, auch. Dieser Hash wurde aus dem Schreiber überträgt auf die (mehrfach) Leser, und der Leser wartet, bis a) die Dateigröße nicht weiter ansteigen und b) die (frisch berechnet) Hash der Datei entspricht den Hash vom Schreiber gesendet.

Wir haben ein ähnliches Problem, aber aus unterschiedlichen Gründen. Wir lesen s-Datei, die auf einem SFTP-Server gesendet wird. Die Maschine das Skript ausgeführt wird, nicht der SFTP-Server.

Was ich getan habe ist es in cron eingerichtet (obwohl eine Schleife mit einem Schlaf funktionieren wird) eine cksum der Datei zu tun. Als der alte cksum entspricht den aktuellen cksum (die Datei hat für die bestimmte Zeit nicht geändert) wissen wir, dass die Schreibvorgänge abgeschlossen sind, und die Datei übertragen.

Just extra sicher zu sein, haben wir nie eine lokale Datei zu überschreiben, bevor ein Backup zu machen und nur Transfer überhaupt, wenn die Remote-Datei zwei cksums in einer Reihe hat, die übereinstimmen, und dass cksum nicht die lokale Datei entspricht.

Wenn Sie Code-Beispiele benötigen, ich bin sicher, dass ich sie graben kann.

Die Shell Ihr Prädikat in Worte spaltet. Schnappen sie alle mit $@ wie in dem folgenden Code:

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

Ausgabe:

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

Schade ist das Typoskript nicht so interessant wie es in Echtzeit zu beobachten.

Ok ... das ist ein bisschen whacky ...

Wenn Sie die Kontrolle über die Datei haben: Sie könnten in der Lage sein, einen ‚Named Pipe‘ zu schaffen hier. So (je nachdem, wie das Schreibprogramm arbeitet) können Sie die Datei in einer synchronisierten Art und Weise überwachen.

In seiner einfachsten Form:

Erstellen Sie die Named Pipe:

mkfifo file.txt

, um den synchronisierten Empfänger ein:

while :
do
    process.sh < file.txt
end

Erstellen Sie einen Test Absender:

echo "Hello There" > file.txt

Die ‚process.sh‘ ist, wo Ihre Logik geht: Dies wird blockiert, bis der Sender seinen Ausgang geschrieben hat. In der Theorie wird der Schriftsteller Programm nicht brauchen modifiying ....

ACHTUNG: wenn der Empfänger aus irgendeinem Grund nicht ausgeführt wird, können Sie den Absender am Ende blockiert

Nicht sicher, sie paßt Ihre Anforderung hier, aber vielleicht lohnt einen Blick in sein.

oder synchronisiert zu vermeiden, versuchen 'lsof'?

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

Unter der Annahme, dass Sie nur aus der Datei lesen wollen, wenn nichts anderes ist schriftlich (dh hat der Schreibvorgang beendet) - Sie könnten überprüfen, ob nichts anderes Dateihandle es hat

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top