Shell: while read loop report errors

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Shell: while read loop report errors

Beitrag von Meillo » 06.07.2017 10:58:01

Hoi,

meist antworte ich ja in diesem Thema, aber hier habe ich mal eine Frage. ;-)

Ich habe ein Script in der Art:

Code: Alles auswählen

find ... | while read f ; do
    check "$f" || echo failure
done
exit $?
Ich will also durchs Dateisystem laufen und alle Dateien, die den find-Kriterien entsprechen, auf eine Weise pruefen. Wenn der Check fehlschlaegt soll eine Meldung ausgegeben werden, zudem soll dann der Exit-Status am Ende nicht-Null sein. Wichtig ist, dass die Pruefung ganz durchlaeuft und nicht beim ersten Fehler aussteigt.

Das Problem ist, dass die Bash die Schleife in einer Subshell ausfuehrt (sonst koennte ich einfach eine Variable setzen). Aber im Kern ist es schon das: Ich muss mir irgendwie merken, wenn ein Check fehlgeschlagen ist, um es am Ende zu wissen.

Den ganzen Ouput in eine Variable saugen und schauen, ob die leer ist, will ich nicht, weil der Job lange laeuft und ich die Ausgaben gerne on-the-fly haette.

Temporaere Dateien waeren auch noch eine Loesung ... aber halt eine Notloesung.

Ich dachte, ich koennte in der Schleife sowas verwenden:

Code: Alles auswählen

trap 'exit 1' 0 1 2 3 15
Das tut aber (aus mir nicht ersichtlichen Gruenden) nicht.

Ideen und Vorschlaege sind willkommen!


P.S.
Das Script beinhaltet aus Performancegruenden Bashisms und erfordert damit sowieso schon die Bash. Folglich nehme ich dieses Mal (wenn auch ungern) auch Bash-spezifische Loesungen an. ;-)
Use ed once in a while!

tobo
Beiträge: 1989
Registriert: 10.12.2008 10:51:41

Re: Shell: while read loop report errors

Beitrag von tobo » 06.07.2017 12:37:15

Sowas in der Art vielleicht?

Code: Alles auswählen

error=0; shopt -s lastpipe; find ... | while read f ; do check "$f" || { error=$?; echo failure; } done; exit $error

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

Re: Shell: while read loop report errors

Beitrag von Meillo » 06.07.2017 13:23:46

Danke, ``lastpipe'' sieht gut aus, gibt's allerdings erst seit bash-4.2 (2011-02).

Die Alternativen sind momentan also bash >= 4.2 zu fordern (sollte wohl kein grosses Problem sein) oder temporaere Dateien zu nutzen.


Edit: Dies ist die beste Eroerterung der Optionen, die ich gefunden habe: https://stackoverflow.com/a/37230845
Use ed once in a while!

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

Re: Shell: while read loop report errors

Beitrag von Meillo » 06.07.2017 14:19:45

Ist ja ``nett'', meine bash 4.2.37(1)-release (oldoldstable) rennt in einen Segfault wenn ich `shopt -s lastpipe' aktiviere. 8O Das scheint mir noch nicht recht ausgereift zu sein.

Ich mache es dann doch besser mit Tempfiles.
Use ed once in a while!

owl102

Re: Shell: while read loop report errors

Beitrag von owl102 » 06.07.2017 15:15:19

Wie wäre es mit

Code: Alles auswählen

while read line
do
  ...
done <<< $(find ...)
Dann wird keine Subshell erzeugt und du kannst fleißig Variablen setzen, die am Ende der Schleife immer noch gültig sind.

Siehe auch: http://tldp.org/LDP/abs/html/x17837.html

breakthewall
Beiträge: 507
Registriert: 30.12.2016 23:48:51

Re: Shell: while read loop report errors

Beitrag von breakthewall » 06.07.2017 15:26:06

Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
Das Problem ist, dass die Bash die Schleife in einer Subshell ausfuehrt (sonst koennte ich einfach eine Variable setzen). Aber im Kern ist es schon das: Ich muss mir irgendwie merken, wenn ein Check fehlgeschlagen ist, um es am Ende zu wissen.
Warum unbedingt eine Subshell? Das verhindert die einfache Verarbeitung von Exitcodes.

Dafür könnte man auch ein Array nutzen:

Code: Alles auswählen

while read -r line; do check "$line" || FAIL+=("$line"); done < <(find . -type f); printf "%s\n" "${FAIL[@]}"
So hast in jenem Array stets jede fehlgeschlagene Datei samt Pfad, und kannst das dann flexibel weiterverarbeiten.
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
Den ganzen Ouput in eine Variable saugen und schauen, ob die leer ist, will ich nicht, weil der Job lange laeuft und ich die Ausgaben gerne on-the-fly haette.
Man kann doch auch beides zugleich haben. Und was heisst on-the-fly? In welcher Weise? Da fehlen so viele Informationen. Besser wäre das Shellscript einfach zu posten, dann weiß man wenigstens was hier exakt passiert und miteinander interagiert.
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
Ich dachte, ich koennte in der Schleife sowas verwenden:

Code: Alles auswählen

trap 'exit 1' 0 1 2 3 15
Das tut aber (aus mir nicht ersichtlichen Gruenden) nicht.
Weil eine trap nicht so verwendet wird. Die steht idealerweise am Anfang des Shellscriptes, oder entsprechend vor dem Codeabschnitt auf den sie explizit reagieren soll, jedoch nicht in einer Schleife. Nebenbei erwähnt gibt es bei einer trap keine 0, wo man alternativ das Pseudosignal EXIT nutzen könnte, was dann auslöst sobald das Shellscript auch nur irgendwie endet.
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
P.S.
Das Script beinhaltet aus Performancegruenden Bashisms und erfordert damit sowieso schon die Bash. Folglich nehme ich dieses Mal (wenn auch ungern) auch Bash-spezifische Loesungen an. ;-)
Macht doch nichts. Die Bash ist nicht ohne Grund die Usershell, da man mit einer reinen Posixshell im Alltag nichts großartig anfangen kann, wenn man wirklich etwas mit Anspruch auf die Beine stellen will.
Zuletzt geändert von breakthewall am 06.07.2017 15:30:04, insgesamt 1-mal geändert.

tobo
Beiträge: 1989
Registriert: 10.12.2008 10:51:41

Re: Shell: while read loop report errors

Beitrag von tobo » 06.07.2017 15:29:30

Ich würde dann auch zu dieser "Rückwärtsbefüllung" tendieren:

Code: Alles auswählen

error=0; while read f ; do check "$f" || { error=$?; echo failure; } done < <(find ...); exit $error
Edit:
Oder für sh:

Code: Alles auswählen

error=0; mkfifo f1 || exit; find ... >f1 & while read f ; do check "$f" || { error=$?; echo failure; } done <f1; rm -f f1; exit $error

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

Re: Shell: while read loop report errors

Beitrag von Meillo » 06.07.2017 21:49:39

Danke, owl102 und tobo. Ja, ich denke, das sind die Optionen. Momentan verwende ich noch temporaere Dateien aber die machen die Sache nur umstaendlicher. Ich werde wohl eine der von euch aufgefuehrten Varianten verwenden.

breakthewall hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 15:26:06
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
Ich dachte, ich koennte in der Schleife sowas verwenden:

Code: Alles auswählen

trap 'exit 1' 0 1 2 3 15
Das tut aber (aus mir nicht ersichtlichen Gruenden) nicht.
Weil eine trap nicht so verwendet wird. Die steht idealerweise am Anfang des Shellscriptes, oder entsprechend vor dem Codeabschnitt auf den sie explizit reagieren soll, jedoch nicht in einer Schleife.
Was bedeutet ``nicht so verwendet wird''? Ich sehe eben keinen (logischen) Grund warum man es nicht so verwenden koennen sollte. Es ist doch voellig egal an welcher Stelle im Script und wie oft ich anmerke, dass beim Exit ein Kommando ausgefuehrt werden soll. (In C kann man atexit(3) auch an beliebigen Stellen verwenden.)
Nebenbei erwähnt gibt es bei einer trap keine 0, [...]
Soso ... und was ist dann damit:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap hat geschrieben: The condition can be EXIT, 0 (equivalent to EXIT), or [...]
?
(http://pubs.opengroup.org/onlinepubs/96 ... .html#trap)
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 10:58:01
P.S.
Das Script beinhaltet aus Performancegruenden Bashisms und erfordert damit sowieso schon die Bash. Folglich nehme ich dieses Mal (wenn auch ungern) auch Bash-spezifische Loesungen an. ;-)
Macht doch nichts. Die Bash ist nicht ohne Grund die Usershell, da man mit einer reinen Posixshell im Alltag nichts großartig anfangen kann, wenn man wirklich etwas mit Anspruch auf die Beine stellen will.
Ach komm schon, meinst du, du koenntest mich ueberzeugen, dass ich kuenftig fuer die Bash statt fuer alle Shells programmiere? Und gleichzeitig scheinst du mir abzusprechen, dass ich in meinem Shell-Alltag ``etwas mit Anspruch auf die Beine stellen'' koennte. Aber wahrscheinlich liegt das daran, dass ``etwas mit Anspruch'' fuer dich eine andere Bedeutung hat als fuer mich ... Ich jedenfalls komme meist ganz gut zurecht und denke, dass schon hin und wieder auch mal ``etwas mit Anspruch'' dabei sein wird, angesichts der Anzahl und Vielfalt, die ich an Shellscripten schreibe. Wobei, wahrscheinlich hast du doch recht, denn meine Scripte sind in der Regel simpel -- jedenfalls strebe ich das an. Wenn ich mir das so ueberlege, dann koennte ich von dir aber wohl doch noch was lernen, um mit der Bash mal ``wirklich etwas mit Anspruch auf die Beine [zu] stellen''.

Nein, doch nicht! Bleib du nur bei deiner Bash. Ich bin nun schon viele Jahre ohne sie ausgekommen, bis jetzt mit diesem einen Script fuer jemand anderen, das problemlos laufen wuerde, waere es nicht fuer die Bash sondern fuer eine ksh ... Das ist doch der Punkt: meine ganzen Probleme haben erst mit der Bash begonnen, weil die die Schleife in einer Subshell ausfuehrt, was nicht noetig ist und folglich andere Shells auch nicht tun. Ach, waere ich bloss in meiner Welt geblieben! :roll:
Use ed once in a while!

tobo
Beiträge: 1989
Registriert: 10.12.2008 10:51:41

Re: Shell: while read loop report errors

Beitrag von tobo » 06.07.2017 22:00:23

Wobei die Subshell aber nicht durch die Schleife, sondern durch die Pipe entsteht. Genau wie bei mksh!?

breakthewall
Beiträge: 507
Registriert: 30.12.2016 23:48:51

Re: Shell: while read loop report errors

Beitrag von breakthewall » 08.07.2017 19:12:02

Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 21:49:39
Was bedeutet ``nicht so verwendet wird''? Ich sehe eben keinen (logischen) Grund warum man es nicht so verwenden koennen sollte. Es ist doch voellig egal an welcher Stelle im Script und wie oft ich anmerke, dass beim Exit ein Kommando ausgefuehrt werden soll. (In C kann man atexit(3) auch an beliebigen Stellen verwenden.)
Du führst die trap dauerhaft wieder und wieder und einer Schleife aus, dass ist egal wie man nimmt nicht richtig.
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 21:49:39
Soso ... und was ist dann damit:
Das ist in der bash Manpage nicht dokumentiert, wo stattdessen auf EXIT verwiesen wird. Es gibt für trap auch keine separate Manpage, da es hier um ein bash-Buildin geht mit eigenen Optionen. Das was da herausgesucht hast, betrifft eine Binary namens trap, die es aber nicht mal unter Debian gibt.
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 21:49:39
Ach komm schon, meinst du, du koenntest mich ueberzeugen, dass ich kuenftig fuer die Bash statt fuer alle Shells programmiere? Und gleichzeitig scheinst du mir abzusprechen, dass ich in meinem Shell-Alltag ``etwas mit Anspruch auf die Beine stellen'' koennte. Aber wahrscheinlich liegt das daran, dass ``etwas mit Anspruch'' fuer dich eine andere Bedeutung hat als fuer mich ... Ich jedenfalls komme meist ganz gut zurecht und denke, dass schon hin und wieder auch mal ``etwas mit Anspruch'' dabei sein wird, angesichts der Anzahl und Vielfalt, die ich an Shellscripten schreibe. Wobei, wahrscheinlich hast du doch recht, denn meine Scripte sind in der Regel simpel -- jedenfalls strebe ich das an. Wenn ich mir das so ueberlege, dann koennte ich von dir aber wohl doch noch was lernen, um mit der Bash mal ``wirklich etwas mit Anspruch auf die Beine [zu] stellen''.

Nein, doch nicht! Bleib du nur bei deiner Bash. Ich bin nun schon viele Jahre ohne sie ausgekommen, bis jetzt mit diesem einen Script fuer jemand anderen, das problemlos laufen wuerde, waere es nicht fuer die Bash sondern fuer eine ksh ... Das ist doch der Punkt: meine ganzen Probleme haben erst mit der Bash begonnen, weil die die Schleife in einer Subshell ausfuehrt, was nicht noetig ist und folglich andere Shells auch nicht tun. Ach, waere ich bloss in meiner Welt geblieben! :roll:
Wie kann man als Moderator solch einen Unsinn posten? Du solltest deine Probleme für dich behalten, und dich nicht laufend erhaben aufführen. Deine fachlichen Qualitäten sind nicht so ausgebaut wie du glaubst, ebenso machst in vielen Fällen im Bezug auf die Shell gravierende Designfehler, die nachhaltig zu ernsten Problemen führen können. Aber es ist letztlich dein Bier wenn dich das stört, dass man dir mal die Probleme aufzeigt, ich muss dir nicht helfen. Und wer ein solches Problem mit der bash hat, die nun mal faktisch unter nahezu allen unixioden Systemen die Standard-User-Shell ist, der sollte vl. mal an sich arbeiten. Die Posix-Shells werden nahezu nur für Systemscripte genutzt, und sind sonst erheblich in ihren Fähigkeiten eingeschränkt. Oder was meinst warum es eine ksh, zsh oder bash gibt? Aber was weiß ich schon, muss ja nur professionell damit arbeiten. Nebenbei ist die ksh überaus bash kompatibel aufgrund des Ursprungs. Und der einzige Grund warum hier eine Subshell ausgeführt ist, ist der, dass das deinerseits so definiert wurde. Wie kommt man dann dazu sich über das Ergebnis zu beschweren, und der bash die Schuld zu geben? Muss man nicht verstehen.

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

Re: Shell: while read loop report errors

Beitrag von Meillo » 08.07.2017 20:07:42

breakthewall hat geschrieben: ↑ zum Beitrag ↑
08.07.2017 19:12:02
Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 21:49:39
Was bedeutet ``nicht so verwendet wird''? Ich sehe eben keinen (logischen) Grund warum man es nicht so verwenden koennen sollte. Es ist doch voellig egal an welcher Stelle im Script und wie oft ich anmerke, dass beim Exit ein Kommando ausgefuehrt werden soll. (In C kann man atexit(3) auch an beliebigen Stellen verwenden.)
Du führst die trap dauerhaft wieder und wieder und einer Schleife aus, dass ist egal wie man nimmt nicht richtig.
Du sagst mir, es sei nicht richtig, aber du begruendest nicht wieso. *Warum* sollte ich die Trap nicht mehrfach setzen? Warum soll das falsch sein? Vielleicht ist es nicht ueblich, aber warum sollte ich es nicht tun duerfen?

(Mein Vergleich mit atexti(3) war nicht recht passend. Es ist eher wie signal(2).)

Meillo hat geschrieben: ↑ zum Beitrag ↑
06.07.2017 21:49:39
Soso ... und was ist dann damit:
Das ist in der bash Manpage nicht dokumentiert, wo stattdessen auf EXIT verwiesen wird. Es gibt für trap auch keine separate Manpage, da es hier um ein bash-Buildin geht mit eigenen Optionen. Das was da herausgesucht hast, betrifft eine Binary namens trap, die es aber nicht mal unter Debian gibt.
Das was ich herausgesucht habe ist die Beschreibung des Shell-Builtins `trap' im POSIX-Standard ... an dem sich die Bash orientiert und den sie (wenn auch vielleicht nicht vollumfaenglich) implementiert.

Wie kann man als Moderator solch einen Unsinn posten? Du solltest deine Probleme für dich behalten, und dich nicht laufend erhaben aufführen.
Meine Sicht der Dinge:

Ich habe im Eingangspost angemerkt, dass ich dieses Mal (anders als sonst) auch an Bash-spezifischen Loesungen interessiert bin, um Irritationen vorweg zu nehmen, weil ich sonst nie an Bash-spezifischen Loesungen interessiert bin. Ich habe mir dabei erlaubt ein ``ungern'' einzubauen.
Meillo hat geschrieben: P.S.
Das Script beinhaltet aus Performancegruenden Bashisms und erfordert damit sowieso schon die Bash. Folglich nehme ich dieses Mal (wenn auch ungern) auch Bash-spezifische Loesungen an. ;-)
Daraufhin sind einige sachliche Antworten von anderen gekommen und eine an mehreren Stellen provokante Antwort von dir.
breakthewall hat geschrieben: Macht doch nichts. Die Bash ist nicht ohne Grund die Usershell, da man mit einer reinen Posixshell im Alltag nichts großartig anfangen kann, wenn man wirklich etwas mit Anspruch auf die Beine stellen will.
Gut, vielleicht hast du dich von meiner anfaenglichen Aeusserung provoziert gefuehlt, ich war es nach deiner Antwort ganz sicher. Warum willst du hier missionieren, wo ich doch sicher verstaendlich in meinen Posts zur Shell zum Ausdruck bringe, dass ich nur an portablem Shellprogrammieren interessiert bin? Jedenfalls habe ich deine Formulierungen nicht einfach hingenommen, sondern habe zurueck geschossen ... hatte wohl einen schlechten Tag.

... Eigentlich hat es schon mit deinem ``Weil eine trap nicht so verwendet wird.'' begonnen bei mir emotional zu werden. Diese Behauptung als absolute Tatsache hinzustellen ohne sie zu begruenden. Kein Wunder, dass das zur Eskalation fuehren musste. Wenn du das in gewaltfreier Sprache formuliert und sachlich begruendet haettest, dann haette daraus vielleicht eine gute Diskussion entstehen koennen, aber so hat es meine Emotionen aufschaeumen lassen.

breakthewall hat geschrieben: Deine fachlichen Qualitäten sind nicht so ausgebaut wie du glaubst, ebenso machst in vielen Fällen im Bezug auf die Shell gravierende Designfehler, die nachhaltig zu ernsten Problemen führen können.
Ich bitte dich, dass du mich an den jeweiligen Stellen sachlich begruendet darauf hinweist.
Use ed once in a while!

Antworten