Seite 1 von 1

If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 11:55
von bunter fisch
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?

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 12:03
von StephanS
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.

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 12:28
von framp
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

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 13:45
von bunter fisch
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.

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 13:58
von framp
Zeige mal den Code ;)

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 14:05
von bunter fisch
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?

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 14:33
von framp
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.

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 14:42
von bunter fisch
Ändert leider auch nichts.

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 14:52
von framp
Zeige mal was in Deiner Inputdatei steht.

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 15:12
von abgdf
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?

Re: If in einer Endlosschleife geht nicht

Verfasst: 3. Okt 2018, 22:35
von robi
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