Wie mit NFS Latenz in Shell-Skripten behandeln
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?
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