bash read

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

bash read

Beitrag von rsi » 23.01.2015 06:13:55

Hallo,

ich habe unter Debian (wheezy) ein Problem mit meinen Scripten.
Ich benutze in verschiedenen (bash) shell scripten "while read var" um verschiedene (Text) Dateien einzulesen und zu verarbeiten. Leider ist mir jetzt schon öfter passiert, dass in der eingelesenen Zeile das erste Zeichen verschwunden ist. Ich habe zum Test vorher die Dateien mit cat ausgegeben, damit ich sicher sein konnte, dass es nicht am Inhalt liegt.
Als Not-Lösung umgehe ich jetzt read und lese die Dateien mit sed zeilenweise ein, was natürlich ein wesentlich höherer (unnötiger) Aufwand ist.
Ich habe es vorher auch schon mit sync versucht, ob evtl. irgend was nicht richtig läuft, aber kein unterschied. Und, es tritt sporadisch auf, was extrem schlecht nachvollziehbar ist.

Hat jemand eine Idee, ob es da einen Bug bei "while read var" gibt? Oder hat sonst eine Idee, woran das liegen könnte?
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

pferdefreund
Beiträge: 3799
Registriert: 26.02.2009 14:35:56

Re: bash read

Beitrag von pferdefreund » 23.01.2015 10:41:28

Mal die entsprechenden Dateien mit nem hexeditor öffnen. Eventuell ist da ja was drin, was kein gültiges Zeichen für die Tastatur ist ?
Low-Value ist so ein Kandidat und im normalen Editor einfach nicht sichtbar. Oder auch irgendwelche Drucksteuerzeichen wie NewPage, Newline usw.

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 23.01.2015 15:02:25

Ist bei den Dateien nicht möglich. Die wurden von mir selber erstellt und mit filter (sed) und echo pipe in die Datei(en) ausgegeben.
Und bei den meisten sonstigen Input-Dateien handelt es sich um Linux Log Dateien. Das würde auffallen, wenn dort andere Zeichen vorhanden wären, da ich diese auch ja auch noch anschaue (mit cat oder tail).
Ich hatte auch erst die Vermutung, dass da Zeichen sind, die etwas verschlucken. Aber nach mehreren Tests direkt von der Console ergab es keine Probleme. Keine fremden Zeichen, keine falschen Zeilen-Ende, etc. pp.
Wie schon geschrieben, so wie ich es zur Zeit mache (mit sed zeilenweise einlesen), geht es ohne Probleme und es werden auch keine Zeichen verschluckt. Deshalb wundert es mich auch, dass es nur bei "while read var" passiert und auch nicht immer, wie es scheint.

Ich überlege aber auch schon seit längerem, das Ganze auf Perl umzuschreiben, da aus ein paar kleinen Scripte inzwischen mehrere große geworden sind und es wohl mit Perl etwas optimaler funktionieren würde. Wäre wohl der einzige vernünftige Ausweg.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: bash read

Beitrag von newdeb » 24.01.2015 07:10:15

Vielleicht hilft

Code: Alles auswählen

while IFS=$'\n' read -r var

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 24.01.2015 11:05:28

Danke für den Tipp, ich werde mal versuchen den "Internal Field Separator" zu ändern und sehen was passiert.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 26.01.2015 10:18:46

Hat leider alles nichts geholfen.
Ich vermute langsam einen Bug in der bash read Funktion, denn anders kann ich es mir nicht mehr erklären. Die Dateien sind jeweils sauber. Ich habe es zum Vergleich mit "while read var" und über sed probiert und mit sed passieren die Fehler nicht.
Seltsamerweise scheint dies nur zu passieren, wenn ich es in einem Script laufen lasse. Mache ich das gleiche auf der Konsole, passiert der Fehler nicht. Wobei ich im Script temp. Dateien zur Aus-/Eingabe nutze. Was aber auch nicht da Problem sein kann, da ich es auch mit statischen Dateien probiert habe.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

rendegast
Beiträge: 15041
Registriert: 27.02.2006 16:50:33
Lizenz eigener Beiträge: MIT Lizenz

Re: bash read

Beitrag von rendegast » 26.01.2015 11:16:19

Ich vermute ein Problem mit den Eingangsdaten.
rsl hat geschrieben: ... zum Test vorher die Dateien mit cat ausgegeben, damit ich sicher sein konnte, dass es nicht am Inhalt liegt.

Code: Alles auswählen

cat -A
mfg rendegast
-----------------------
Viel Eifer, viel Irrtum; weniger Eifer, weniger Irrtum; kein Eifer, kein Irrtum.
(Lin Yutang "Moment in Peking")

Benutzeravatar
Meillo
Moderator
Beiträge: 9236
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: bash read

Beitrag von Meillo » 26.01.2015 11:20:28

Ich halte es fuer sehr unwahrscheinlich, dass das `read' der bash einen solchen Fehler hat. Es ist sehr viel wahrscheinlicher, dass der Fehler in deinem Code ist. (Das sagt die Erfahrung.)

Kannst du bitte mal den Code und Beispieldaten posten, dann koennen auch wir das mal laufen lassen und nach dem Problem suchen. Ich will erstmal das Problem *sehen*, nicht nur davon erzaehlt bekommen. Und dann koennen wir das Script mit verschiedenen Versionen der Bash testen, evtl. mit einer ksh oder dash ... denn dass verschiedene Shells den gleichen Bug haben ist noch viel, viel unwahrscheinlicher. Damit ist es dann schon fast klar, dass der Fehler in deinem Code liegen musst. Und dann folgen wir einfach Linus' Law: ``Given enough eyeballs, all bugs are shallow.''

Ohne handfeste Grundlage fuehle mich mich ausser Stande zu helfen ... und auf blindes Rumgerate habe ich wenig Lust.
Use ed once in a while!

uname
Beiträge: 12403
Registriert: 03.06.2008 09:33:02

Re: bash read

Beitrag von uname » 26.01.2015 15:39:31

Sehe ich ähnlich. Endlich dass mal wieder jemand, der ein nettes Script postet, wo man nicht nur die Fehler sucht, sondern gleich ein paar unnötige Optimierungen einbaut bzw. Alternativen aufzeigt ;-)

Benutzeravatar
Meillo
Moderator
Beiträge: 9236
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: bash read

Beitrag von Meillo » 26.01.2015 16:01:40

So ein (scheinbar) verzwicktes Problem finde ich auch richtig reizvoll. Ich verfolge den Thread schon seit Beginn und brenne darauf zu erfahren woran es letztlich liegt ... entweder indem andere den Fehler finden und mir die Ursache mitteilen, oder noch besser, wenn ich mich selbst ins Gewuehle stuerze. Ein solches Problem ist wie eine Wundertuete: Man weiss nie was man drin findet! :-D
Use ed once in a while!

sebastian_rose
Beiträge: 16
Registriert: 30.04.2004 12:23:16
Wohnort: Hannover
Kontaktdaten:

Re: bash read

Beitrag von sebastian_rose » 26.01.2015 20:30:12

Ich kann das nicht wirklich nachvollziehen.
Denke aber, dass das Problem von gemischten Zeilenenden herrührt. Einige Zeilen enden wahrscheinlich auf \r\n statt auf \n (weshalb ein Kollege oben 'cat -A' zur Ausgabe der Eingangsdaten vorgeschlagen hat - poste doch mal das Ergebnis).

Datei mit gemischten Zeilenenden erstellen:

Code: Alles auswählen

sh# perl -e 'print "abc 123\r\nabc 123\nabc 123\r\nabc 123\n";' > abc.txt
sh# cat abc.txt | while read var; do echo $var; done       # Kein Zeichen scheint zu fehlen
abc 123
abc 123
abc 123
abc 123
# Aber im Fehlerfall:
sh# cat abc.txt | while read var; do print $var; done
"rror: no such file "abc 123
Error: no such file "abc 123"
"rror: no such file "abc 123
Error: no such file "abc 123"
Da fehlen Zeichen. Wie Du siehst, wird durch \r der Cursor an den Zeilenanfang gesetzt, und dann das schließende Anführungszeichen dort hingesetzt.

Poste doch mal die relevanten Zeilen.
Zuletzt geändert von sebastian_rose am 26.01.2015 20:35:25, insgesamt 1-mal geändert.

sebastian_rose
Beiträge: 16
Registriert: 30.04.2004 12:23:16
Wohnort: Hannover
Kontaktdaten:

Re: bash read

Beitrag von sebastian_rose » 26.01.2015 20:34:44

PS:

Code: Alles auswählen

sh# cat -A abc.txt
abc 123^M$
abc 123$
abc 123^M$
abc 123$
^M == \r

Der Emacs zeigt \r ebenfalls als ^M an, wenn die Zeilenenden gemischt sind.

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 26.01.2015 22:15:50

Also...

Ich habe das Problem jetzt eingrenzen können.
Ob es ein Bug ist, oder so richtig ist, kann ich gerade nicht einschätzen.
Tatsache ist, die Eingabe-Dateien sind alle korrekt, da ja kurz vorher erstellt und mehrmals kontrolliert auf verschiedene Weise. Da sed diese auch korrekt einlist, liegt es nicht daran.
Aber... und da kommt der Punkt wo manche Recht haben und vielleicht auch nicht. Da bin ich mir gerade nicht sicher.
Es liegt am Code, aber nicht am "while read var", sondern in dieser Schleife rufe ich ein weiteres Script von mir auf, das die Daten verarbeitet, die eingelesen werden. In diesem Script gibt es EBENFALLS einen Aufruf von "read", aber nicht als Schleife, sondern als interaktive Eingabe mit Timeout. Und wenn dieses Script beendet wird, wird anscheinend in der vorherigen "while read var" Schleife etwas falsch eingelesen.
Ich habe es mehrmals kontrolliert, sowohl von der Konsole (wo die Schleife alles richtig einliest), als auch im Script, wo ich ein anderes Script zum Test aufrufe, wo zur Kontrolle nur die Daten noch mal ausgegeben werde, ohne ein "read" aufzurufen. Und DA wird dann auch alles korrekt eingelesen!

Die Scripte selbst sind mir zu umfangreich, um sie komplett zu posten (und enthalte Daten, die niemanden etwas angehen), aber ich kann zumindest posten, was ich gemacht habe.

Teil von Script A, wo der Fehler passiert:

Code: Alles auswählen

# Script A
InputFile=$(mktemp)
FunktionWelcheDieDatenInDieDateiSchreibt()   # Es sind numerische Daten und alles korrekt! Keine extra Zeichen, etc. pp.
while read lLine; do
# hier ein paar enfache Tests mit egrep, über den Inhalt der Daten
  ScriptB_Aufrufen "$lLine"    # hier passiert wohl der Fehler
done < $InputFile
rm -r $InputFile
Mehr ist es im Prinzip nicht.
In dem Externem Script werden die Daten verarbeitet und je nach Inhalt, kommt eine interaktive Abfrage.

Code: Alles auswählen

# Script B
# Daten auswerten und je nach interaktive Abfrage verarbeiten
  lDaten=$(echo "$1" | egrep "nach bestimmten inhalt suchen")
  if [ -n "$lDaten" ]; then
    # hier kommt das Problem
    echo "Nur ein Hinweistest zur Abfrage ausgeben..."
    read -p "Trotzdem verarbeiten? (j/N)" -N 1 -t 30
    echo ""
    if [ $? -eq 0 ] && [ "$REPLY" = "j" -o "$REPLY" = "J" ]; then
       # hier werden die Daten normal in andere Datei ausgegeben
    fi
  else
    # daten in neue Datei schreiben
  fi
So, und sobald hier das Script B in die interaktive "read" Anweisung verzweigt, wird im Script A etwas in der Schleife falsch eingelesen, bzw. nur das 1. Zeichen der nächsten Zeile übersprungen. Warum, ist mir nicht klar.
So, aber... wenn ich in Script A die "while read var" Schleife durch "sed" ersetze, wie folgt...

Code: Alles auswählen

# Ersatz für while read var
nLines=$(sed -n $= $InputFile)
[ -z "$nLines" ] && nLines=0
for (( i=1; i<=$nLines; i++ ))
do
        lLine=$(sed -n "${i},${i}p" $InputFile)
# hier ein paar enfache Tests mit egrep, über den Inhalt der Daten
  ScriptB_Aufrufen "$lLine"    # hier passiert wohl der Fehler
done
... gibt es keinen Fehler, die Zeilen werden korrekt eingelesen und alles funktioniert.

Frage ist jetzt, ist es erlaubt, in einer "while read var" Schleife nochmal "read" interaktive (in einem anderem Script) aufzurufen, oder ist es ein Bug? Und das weiß ich jetzt nicht, vielleicht kann da jemand eine Antwort drauf geben.

Gruß

P.S.
Beispieldaten...
Es sind nur Zahlenwerte.

Code: Alles auswählen

34.545.2323
108.343
39.3003.4004.500
Also mit unterschiedlicher Länge, teilweise durch einen oder mehrere Punkte getrennt. Und es können zwischen einer und mehreren Tausend Zeilen sein!
IFS ist korrekt auf \n gesetzt, die Daten sind einwandfrei, da ich sie auf der Konsole mit "while read var" ohne Problem einlesen und ausgeben konnte (aber ohne Script B aufruf!).
Auch cat hat keine Fehler in den Eingabe-Daten angezeigt und auch im vim wurde nichts angezeigt. Also Daten korrekt!

Ach so... und zur Sicherheit!
Debian wheezy (uptodate)

Code: Alles auswählen

Linux sabretooth 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u1 x86_64 GNU/Linux
Bash Version

Code: Alles auswählen

GNU bash, version 4.2.37(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Zuletzt geändert von rsi am 26.01.2015 22:34:11, insgesamt 1-mal geändert.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

Benutzeravatar
Meillo
Moderator
Beiträge: 9236
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: bash read

Beitrag von Meillo » 26.01.2015 22:33:34

Das `-N 1' scheint mir verdaechtig zu sein. Fehlen vielleicht zwei Zeichen wenn du `-N 2' verwendest? ;-)
Use ed once in a while!

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 26.01.2015 22:38:16

Das könnte ich mal testen, aber laut "help read" wollte ich es so auch einsetzen.
-N nchars return only after reading exactly NCHARS characters, unless EOF is encountered or read times out, ignoring any delimiter
Da das Script B auch per Cron mit Daten versorgt wird, oder manuell, wollte ich verhindern, dass es an der Abfrage hängen bleibt.

Ich sehe sowieso gerade einen Fehler, der mir bis jetzt nicht aufgefallen ist.

Code: Alles auswählen

[ $? -eq 0 ]
... nach dem read prompt kann nicht funktionieren, da ich dazwischen noch mal "echo" aufgerufen habe. :)


Nachtrag:
Gerade getestet, das -N1 bei dem read prompt ist schuld. Oh man... und ich such da wie blöd herum. Danke für den Hinweis! :THX:
Hmm... ist das nun korrekt, oder ein Bug? Logisch gesehen müsste das korrekt sein, aber praktisch gesehen, ist das etwas, was man kaum bemerkt.
Wie könnte ich jetzt die interaktive Abfrage (prompt) mit mit Timeout einbauen? :)

Hmm... ich werde wohl den read prompt entfernen, die Daten extra speichern und diese dann rein manuell verarbeiten müssen. Geht wohl nicht anderes, da das Script automatisch laufen soll.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: bash read

Beitrag von Cae » 26.01.2015 23:19:06

Code: Alles auswählen

...
tty -s && {
# interaktiver Code
}
...
oder je nach Vorlieben auch in einen if-Block eingepackt.

Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 26.01.2015 23:30:44

Ok, aber mit tty müsste ich ssh -t aufrufen, da ich mich dazu auf meinem Server mit ssh einloggen muss. :)
Ich hoffe zumindest, dass es dann mit SSH funktioniert.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: bash read

Beitrag von Cae » 27.01.2015 03:49:41

Naja, du hast halt beim aktuellen Design nur die Unterscheidungsmoeglichkeit zwischen TTY/kein TTY. Es gibt keine Moeglichkeit, herauszufinden, ob stdin nun eine Pipe der Shell ist, die auf eine Datei zeigt, oder ob da jemand z.B. per

Code: Alles auswählen

$ echo foo | ssh user@host some/script
Daten ueber eine anders geartete Pipe reinschiebt. Man wuerde an dieser Stelle entweder den interaktiven Kram per globalem Flag deaktivieren (-f, --force waere da ueblich fuer "mach' einfach, was du fuer richtig haelst"). Oder man macht das interaktive read direkt aus /dev/tty, was dann schlimmstenfalls fuer immer blockt, aber keine Eingangsdaten wegfruehstueckt.

Sofern du dein Skript ueber eine interaktive Shell startest, hast du sehr wahrscheinlich ein TTY, auch ohne explizites Anfordern per ssh -t.

Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
Meillo
Moderator
Beiträge: 9236
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: bash read

Beitrag von Meillo » 27.01.2015 08:16:26

rsi hat geschrieben: Gerade getestet, das -N1 bei dem read prompt ist schuld. Oh man... und ich such da wie blöd herum. Danke für den Hinweis! :THX:
Tada! Tada! Tada! :-D


Und nochmal: ``Given enough eyeballs, all bugs are shallow.''
Use ed once in a while!

newdeb
Beiträge: 134
Registriert: 03.02.2011 11:11:21
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Frankfurt

Re: bash read

Beitrag von newdeb » 27.01.2015 19:15:17

Wenn du auf einen anderen Filedeskriptor ausweichst, kommen sich die reads nicht ins Gehege:

Code: Alles auswählen

while read -u3 -r VAR; do 
  echo "$VAR" 
  read -p "Naechste Zeile: " 
  [[ $REPLY != [jJ] ]] && break 
done 3< input

rsi
Beiträge: 31
Registriert: 23.01.2015 05:56:49

Re: bash read

Beitrag von rsi » 27.01.2015 23:35:15

Danke, auch eine Möglichkeit.
Aber ich habe den Prompt jetzt erst mal raus geschmissen, damit das Script automatisch ablaufen kann.
Die anderen Daten werde ich über ein neues Script verarbeiten... so geht es dann auch.
Es gibt Menschen, die Helfen können und es gibt den Rest, die man gleich ignorieren sollte...

Antworten