Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.

If in einer Endlosschleife geht nicht

Alles rund um die verschiedenen Konsolen und shells sowie die Programmierung unter Linux

Moderator: Moderatoren

Antworten
bunter fisch
Member
Member
Beiträge: 77
Registriert: 12. Sep 2017, 10:25

If in einer Endlosschleife geht nicht

Beitrag von bunter fisch » 3. Okt 2018, 11:55

Hallo,

ich habe hier folgendes Script.

Code: Alles auswählen

file=/path/to/file
while true ; do
count=$(cat "$file" | wc -m )
 if [ "$count" -ge 1 ] ; then
  while IFS= read -r zeile ; do 
   echo "$zeile"
   sed -i '1,1 d' "$file"
  done < "$file"
 else
  echo "nichts zu tun"
 fi
done
In die Variable 'count' wird geschrieben wieviel Wörter in einer Textdatei stehen. Mit If wird geprüft ob die Anzahl der Wörter größer 0 ist, wenn ja sollen die Zeilen der Datei ausgegeben und danach gelöscht werden. Falls die Datei leer ist wird angezeigt das nichts zu tun ist (eigentlich soll es dann beendet werden, hab ich für die Versuche geändert). Das ganze steckt in einer Endlosschleife die so lange läuft bis die Datei leer ist.

Problem: If scheint sich anders zu verhalten wenn es in der Endlosschleife steckt oder wenn es "allein" steht. Kommentiere ich die Endlosschleife aus, werden mir alle Zeilen der Datei angezeigt, wenn If in der Endlosschleife steckt, wird "nichts zu tun" angezeigt, auch wenn er ohne Endlosschleife die Datei auswertet. Wie kann das sein?

Werbung:
Benutzeravatar
StephanS
Member
Member
Beiträge: 69
Registriert: 24. Jan 2005, 22:04

Re: If in einer Endlosschleife geht nicht

Beitrag von StephanS » 3. Okt 2018, 12:03

Funktioniert bei mir. Beim ersten Durchgang zeigt er die Datei zeilenweise an und löscht dabei alle Zeilen. Beim zweiten und allen folgenden Durchgängen ist die Datei leer und das Skript zeigt korrekterweise "nichts zu tun" an.

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: If in einer Endlosschleife geht nicht

Beitrag von framp » 3. Okt 2018, 12:28

Funktioniert bei mir auch. Anbei ein Vorschlag wie ich es schreiben wuerde:

Code: Alles auswählen

#!/bin/bash

file=$1
while true ; do
#count=$(cat "$file" | wc -m )
 count=$(wc -m < "$file" )
#if [ "$count" -ge 1 ] ; then
 if (( "$count" >=  1 )) ; then
  while IFS= read -r zeile ; do
   echo "$zeile"
   sed -i '1,1 d' "$file"
  done < "$file"
 else
  echo "nichts zu tun"
 fi
done

bunter fisch
Member
Member
Beiträge: 77
Registriert: 12. Sep 2017, 10:25

Re: If in einer Endlosschleife geht nicht

Beitrag von bunter fisch » 3. Okt 2018, 13:45

Hatte einen Fehler drin. Es wurde sehr oft "nichts zu tun" ausgegeben, aber gaaanz oben im Terminal stand die Ausgabe drin. Hatte ich nicht gesehen.

Ich hab aber noch ein anderes Problem. Wenn ich die Sache etwas abwandle und statt eien Zeile nur mit echo anzeigen diese ausführen lasse (wenn die Zeile ein Kommando enthält) geht das, solange kein && drin ist. Angenommen die Zeile in der Datei sieht so aus:

Code: Alles auswählen

program --input filename --options --output
geht das. Wenn der aber so aussieht

Code: Alles auswählen

program --input filename --options --output && mv output output_mod
wird ständig eine 0 Byte große Datei erstellt. Scheinbar wird das && ignoriert und 'mv' schon ausgeführt bevor 'program' fertig ist. Kopiere ich die Zeile in ein Terminal geht alles wie es soll.


bunter fisch
Member
Member
Beiträge: 77
Registriert: 12. Sep 2017, 10:25

Re: If in einer Endlosschleife geht nicht

Beitrag von bunter fisch » 3. Okt 2018, 14:05

Wovon? Ist das gleiche Script wie oben, nur ohne echo:

Code: Alles auswählen

file=$1
while true ; do
count=$(cat "$file" | wc -m )
if [ "$count" -ge 1 ] ; then
  while IFS= read -r zeile ; do
   "$zeile"
   sed -i '1,1 d' "$file"
  done < "$file"
 else
  echo "nichts zu tun"
 fi
done
Anstatt die Zeile anzuzeigen wird sie ausgeführt - oder sollte zumindest. Oder was für Code meinst du?

Benutzeravatar
framp
Moderator
Moderator
Beiträge: 4270
Registriert: 6. Jun 2004, 20:57
Wohnort: bei Stuttgart
Kontaktdaten:

Re: If in einer Endlosschleife geht nicht

Beitrag von framp » 3. Okt 2018, 14:33

bunter fisch hat geschrieben:
3. Okt 2018, 14:05
Wovon? Ist das gleiche Script wie oben, nur ohne echo:
Nun ja, es kommt auf die Details an :) Nimm mal die Tueddelchen weg.

bunter fisch
Member
Member
Beiträge: 77
Registriert: 12. Sep 2017, 10:25

Re: If in einer Endlosschleife geht nicht

Beitrag von bunter fisch » 3. Okt 2018, 14:42

Ändert leider auch nichts.


abgdf
Guru
Guru
Beiträge: 3113
Registriert: 13. Apr 2004, 21:15

Re: If in einer Endlosschleife geht nicht

Beitrag von abgdf » 3. Okt 2018, 15:12

Mir gefällt dabei nicht, innerhalb einer Schleife, die sich auf eine bestimmte Datei bezieht, mit sed auf derselben Datei rumzuhacken (oder die Datei sonst zu verändern) (Dein "read" kann z.B. versuchen, Zeilen zu lesen, die sed gerade gekillt hat). Das kann bei der Prüfung der Bedingung für die Schleife zu unkontrollierten Ergebnissen führen.
Das zusammen mit der Endlosschleife drumrum macht dann die Verwirrung komplett. ;) Dann wird es auch schwer, den Fehler zu finden. Weil er nicht direkt aus dem Code ablesbar ist, sondern vom Inhalt der verarbeiteten Datei abhängt. So ein Programm kann dann mal laufen, muß aber nicht.
Das alles sollte man vermeiden.

Warum überhaupt zeilenweise? Wenn "wc -m", das sich ja auf die ganze Datei bezieht, was anzeigt, kannst Du auch mit "cat" die Datei ganz ausgeben und sie danach ganz löschen. Oder ist es zeilenweise nötig? Warum?

Benutzeravatar
robi
Moderator
Moderator
Beiträge: 3160
Registriert: 25. Aug 2004, 02:13

Re: If in einer Endlosschleife geht nicht

Beitrag von robi » 3. Okt 2018, 22:35

In Linux lässt sich eine Datei nicht innerhalb eines Befehls auf der Konsole lesen und schreiben, auch nicht wenn es mehrere Befehle sind die mittels Pipe oÄ.. verknüpft sind.

Code: Alles auswählen

LINUX> cat test.txt  > test.txt
cat: test.txt: Eingabedatei ist Ausgabedatei
selbst wenn es scheinbar mal funktioniert und die Shell es nicht erkennt und die Ausführung zuläßt, ist die Datei anschließend in der Regel leer.

Code: Alles auswählen

LINUX> ls -il test.txt
3017895 -rw-r--r-- 1 robi users 900  3. Okt 22:52 test.txt
LINUX> cat test.txt | cat | cat | cat | cat > test.txt
LINUX> ls -il test.txt
3017895 -rw-r--r-- 1 robi users 0  3. Okt 22:53 test.txt
somit kann auch "sed -i" nicht einfach eine Datei ändern. ( genauso wie jeder andere Editor auch, legt sed eine andere Datei an und gibt ihr den original Namen, die originale Datei wird dabei gelöscht.
Zu erkennen an den Inodenummer der Datei, die ändern sich bei einem "sed -i " Aufruf.

Code: Alles auswählen

LINUX> ls -il test.txt
3017864 -rw-r--r-- 1 robi users 2662  3. Okt 21:49 test.txt
LINUX> sed -in '/16/d' test.txt
LINUX> ls -il test.txt
3017895 -rw-r--r-- 1 robi users 2276  3. Okt 21:51 test.txt
Von da her ist dein Script schon im Ansatz unberechenbar und als ganzes ein Bug. Da du während der Ausführung eine Datei die du zum Lesen geöffnet hast durch die Bearbeitung mittels sed löscht und eine neue mit gleichem Namen anlegst, aber weiterhin aus der Orginaldatei (auch wenn schon im Dateisystem gelöscht) durch den immer noch offenen Filehandle und den ebenfalls offenen Cache der Datei vom Prozesses weiter ausließt, und in einer Schleife mit jedem weiterem Aufruf eine vorher schon geänderte Kopie vom letzten Durchlauf mit sed weiter bearbeitest und zwar auf Datenbasis der Orginaldatei.
Je nach dem wie schnell hier Teilprozesse im Script arbeiten, ist es sogar möglich das der Dateiname gelegentlich mal in einem Schleifendurchlauf gar nicht vorhanden ist, bzw unerwartet leer ist. Da innerhalb der Schleife der Name der Datei ständig auf eine andere Inode zeigt, kann sowas durchaus auch noch zu weiteren unberechenbaren Ergebnissen führen, wenn da nicht irgend ein "wait" zB. durch irgendwelche echo-Befehle innerhalb der Schleife dazu führt, das eine kleine Pause zwischen zwei sed Befehlen liegt die auf den gleichen Dateinamen lesen und schreiben .

robi

Antworten