While-Schleife, um zu testen, ob eine Datei in bash vorhanden ist


92

Ich arbeite an einem Shell-Skript, das bestimmte Änderungen an einer txt-Datei nur dann vornimmt, wenn sie vorhanden ist. Diese Testschleife funktioniert jedoch nicht. Ich frage mich, warum. Danke dir!

while [ ! -f /tmp/list.txt ] ;
do
      sleep 2
done

3
Ich kann nicht sagen, dass ich überrascht bin; Diese Schleife versucht nichts zu ändern.
Ignacio Vazquez-Abrams

Das Semikolon ist überflüssig. Inwiefern funktioniert diese Testschleife nicht? Es wird iterativ 2 Sekunden lang in den Ruhezustand versetzt, bis die Datei /tmp/list.txt vorhanden ist.
Jonathan Leffler

5
Funktioniert bei mir - die Schleife wird beendet, wenn die Datei außerhalb des Skripts erstellt wird.

1
Tatsächlich dient diese Schleife nur dazu, zu warten, bis die Datei vorhanden ist. Der Rest meines Skripts nimmt die Änderungen vor ...: p
Zenet

1
Dann funktioniert die while-Schleife, ich bin es nur ... Entschuldigung.
Zenet

Antworten:


142

Wenn Sie sagen "funktioniert nicht", woher wissen Sie, dass es nicht funktioniert?

Sie können versuchen, herauszufinden, ob die Datei tatsächlich vorhanden ist, indem Sie Folgendes hinzufügen:

while [ ! -f /tmp/list.txt ]
do
  sleep 2 # or less like 0.2
done
ls -l /tmp/list.txt

Sie können auch sicherstellen, dass Sie eine Bash-Shell (oder eine verwandte Shell) verwenden, indem Sie 'echo $ SHELL' eingeben. Ich denke, dass CSH und TCSH für diese Schleife eine etwas andere Semantik verwenden.


Warum verwenden Sie die invertierte Dateiprüfung? Sollte nicht stattdessen [-f /tmp/list.txt] verwendet werden?
Valentt

2
@valentt Keine Hew-Schleife sagt wörtlich "solange KEINE Datei existiert, schlafe". Wenn du das 'NICHT' entfernen würdest, würde die Schleife sofort brechen
Kenyakorn Ketsombut

2
in 1 Zeile:while [ ! -f /tmp/list.txt ]; do sleep 2; done; ls -l /tmp/list.txt
DrumM

55

Wenn Sie unter Linux arbeiten und inotify-tools installiert haben, können Sie dies tun:

file=/tmp/list.txt
while [ ! -f "$file" ]
do
    inotifywait -qqt 2 -e create -e moved_to "$(dirname $file)"
done

Dies verringert die Verzögerung, die durch den Ruhezustand verursacht wird, während weiterhin alle "x" Sekunden abgefragt wird. Sie können weitere Ereignisse hinzufügen, wenn Sie davon ausgehen, dass sie benötigt werden.


4
+1 für Effizienz. Pooling mit Schlaf ist hässlich. Für Leute, die inotifywait nicht kennen - es ist im Paket inotify-tools.
Michał Šrajer

7
Das ist ein äußerst praktisches Werkzeug. Für alle, die sich fragen, warum die Schleife ist, ist es wichtig, sich mit möglichen Race-Bedingungen zwischen Erstellung und Warten zu befassen und weil inotifywait --excludeDateinamen herausfiltern muss , aber nicht --includealles außer dem Dateinamen ignorieren muss . Der obige Befehl sollte das -qqArgument anstelle von >&/dev/nullobwohl verwenden.
Craig Ringer

t ist das --timeout, nicht die Häufigkeit der Überprüfung, nein? Der Punkt von inotifywait ist, dass es keine Umfrage gibt
Alex Dean

1
@AlexDean Das Timeout dient dazu, eine Rennbedingung zu verhindern. Das Abrufen im Ruhezustand ist langsam, da die Schleife während des Ruhezustands nicht beendet wird. Inotifywait wird jedoch vor dem Timeout beendet, wenn ein Ereignis auftritt.
Yingted

1
@AlexDean Ja, aber es ist notwendig, eine TOCTTOU-Rennbedingung zu verhindern. Andernfalls kann inotifywaites unbegrenzt hängen bleiben, wenn eine Datei erstellt wird, bevor sie auf Ereignisse wartet.
Yingted

4

Ich hatte das gleiche Problem, setzen Sie die! außerhalb der Klammern;

while ! [ -f /tmp/list.txt ];
do
    echo "#"
    sleep 1
done

Wenn Sie ein Echo in die Schleife einfügen, werden Sie darüber informiert, ob Sie in die Schleife einsteigen oder nicht.


2

Ich bin auf ein ähnliches Problem gestoßen, das mich hierher geführt hat, und ich wollte meine Lösung nur jedem überlassen, der das Gleiche erlebt.

Ich stellte fest, dass cat /tmp/list.txtdie Datei leer wäre , wenn ich sie ausführen würde, obwohl ich sicher war, dass Inhalte sofort in die Datei eingefügt wurden. Es stellt sich heraus, wenn ich sleep 1;kurz vor dem cat /tmp/list.txtes wie erwartet funktioniert hat. Es muss eine Verzögerung zwischen dem Zeitpunkt der Erstellung der Datei und dem Zeitpunkt des Schreibens gegeben haben, oder etwas in dieser Richtung.

Mein letzter Code:

while [ ! -f /tmp/list.txt ];
do
    sleep 1;
done;
sleep 1;
cat /tmp/list.txt;

Hoffe, das hilft jemandem eine frustrierende halbe Stunde zu sparen!


1

Wie bei @ zane-hooper hatte ich ein ähnliches Problem mit NFS. Auf parallelen / verteilten Dateisystemen kann die Verzögerung zwischen dem Erstellen einer Datei auf einem Computer und dem "Sehen" des anderen Computers sehr groß sein, sodass ich nach dem Erstellen der Datei bis zu einer vollen Minute warten kann, bevor die while-Schleife beendet wird (und Es gibt auch einen Nacheffekt davon, dass eine bereits gelöschte Datei "gesehen" wird.

Dies erzeugt die Illusion, dass das Skript "nicht funktioniert" , während es tatsächlich das Dateisystem ist, das den Ball fallen lässt.

Ich habe eine Weile gebraucht, um herauszufinden, ich hoffe, es spart jemandem etwas Zeit.

PS Dies verursacht auch eine ärgerliche Anzahl von "Stale File Handler" -Fehlern.


0

funktioniert mit bash und sh beides:

touch /tmp/testfile
sleep 10 && rm /tmp/testfile &
until ! [ -f /tmp/testfile ]
do
   echo "testfile still exist..."
   sleep 1
done
echo "now testfile is deleted.."

0

Hier ist eine Version mit einer Zeitüberschreitung, sodass die Schleife nach einiger Zeit mit einem Fehler endet:

# After 60 seconds the loop will exit
timeout=60

while [ ! -f /tmp/list.txt ];
do
  # When the timeout is equal to zero, show an error and leave the loop.
  if [ "$timeout" == 0 ]; then
    echo "ERROR: Timeout while waiting for the file /tmp/list.txt."
    exit 1
  fi

  sleep 1

  # Decrease the timeout of one
  ((timeout--))
done

-3

mach es so

while true
do
  [ -f /tmp/list.txt ] && break
  sleep 2
done
ls -l /tmp/list.txt
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.