bash: Liste mit read verarbeiten

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

bash: Liste mit read verarbeiten

Beitrag von paedubucher » 13.10.2019 19:28:15

Ich stehe wieder mal auf dem Shell-Schlauch. Die Aufgabe klingt simpel, hat mich aber doch einige Besuche auf StackOverflow eingebracht: Angenommen, ich habe eine textuelle Liste, über dere Einträge (Zeilen) ich iterieren möchte. Hier ist mein erster naiver Versuch:

Code: Alles auswählen

#!/usr/bin/bash

read TIERE << EOF
    Esel
    Katze
    Elefant
    Hund
EOF

echo "debug --- $TIERE --- debug"

echo $TIERE | while read -d ' ' TIER
do
    echo $TIER
done
Die Ausgabe (wohl aus dem oberen echo (Debug-Statement):

Code: Alles auswählen

debug --- Esel --- debug
Nun bin ich auf einem StackOverflow-Beitrag auf den Tipp gestossen, oben read -d '' zu verwenden:

Code: Alles auswählen

#!/usr/bin/bash

read -d '' TIERE << EOF
    Esel
    Katze
    Elefant
    Hund
EOF

echo "debug --- $TIERE --- debug"

echo $TIERE | while read -d ' ' TIER
do
    echo $TIER
done
Ausgabe:

Code: Alles auswählen

debug --- Esel
    Katze
    Elefant
    Hund --- debug
Esel
Katze
Elefant
Zwischenfazit: Die ganze Liste wird eingelesen, aber nicht über das letzte Element iteriert. Aber was bedeutet read -d '' überhaupt?

Code: Alles auswählen

      -d delim        continue until the first character of DELIM is read, rather than newline
Ist '' nun als EOF zu interpretieren? Und warum wird das letzte Element Hund nicht ausgegeben? Kann mir jemand auf die Sprünge helfen? Vielen Dank!
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

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

Re: bash: Liste mit read verarbeiten

Beitrag von Meillo » 13.10.2019 20:36:40

TL;DR: Du denkst viel zu kompliziert. (Das ist oftmals eine Folge von Stackoverflow.)


Der einfachste Fall ist:

Code: Alles auswählen

while read line; do
	echo "$line" # or do whatever you like with $line
done
Auf diese Weise wird Stdin gelesen, du kannst aber auch in die Schleife reinpipen oder (am Ende, nach ``done'') eine Eingabeumleitung anhaengen.


Btw: Du solltest nicht vergessen, dass die Schleife moeglicherweise in einer Subshell laeuft und damit Variablen, die du darin setzt im Code danach nicht zugreifbar sind. Das sorgt gemeinhin fuer Verwirrung. Wir haben das auch hier im Forum das eine oder andere Mal diskutiert.
Use ed once in a while!

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: bash: Liste mit read verarbeiten

Beitrag von paedubucher » 13.10.2019 21:12:06

OK, den unteren Teil konnte ich schon einmal mit einem Here Document lösen:

Code: Alles auswählen

while read TIER
do
    echo $TIER
done <<< $TIERE
Einfach und übersichtlich, wenn auch nicht POSIX-konform (oder?).

Was ich noch nicht verstehe ist der leere Delimiter oben (-d ''):

Code: Alles auswählen

read -d '' TIERE << EOF
    Esel
    Katze
    Elefant
    Hund
EOF
Ich möchte die Liste gerne oben separat haben, da ich diese ständig erweitern werde. (Hintergrund: Ich habe mir eine kleine CI-Pipeline aufgebaut, und ich möchte oben die einzelnen Skripts laufend ergänzen.)

Nachtrag: So geht es am einfachsten und ohne jegliche Bash-spezifischen Features:

Code: Alles auswählen

#!/bin/sh

TIERE="
    Esel
    Katze
    Elefant
    Hund
"

for TIER in $TIERE
do
    echo $TIER
done
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

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

Re: bash: Liste mit read verarbeiten

Beitrag von Meillo » 13.10.2019 21:42:12

paedubucher hat geschrieben: ↑ zum Beitrag ↑
13.10.2019 21:12:06
OK, den unteren Teil konnte ich schon einmal mit einem Here Document lösen:

Code: Alles auswählen

while read TIER
do
    echo $TIER
done <<< $TIERE
Einfach und übersichtlich, wenn auch nicht POSIX-konform (oder?).
Das ist kein Here-Document (<<), sondern ein Here-String (<<<). Ersteres ist POSIX-konform, zweiteres AFAIK nicht.

Du kannst es aber ebenso so machen:

Code: Alles auswählen

...
done <<!
$TIERE
!
Das ist POSIX-konform und inhaltlich gleich.


Btw: Kein Grund fuer Grossbuchstaben fuer Variablennamen ... vielmehr eher ein Grund dagegen: Variablennamen in Grossbuchstaben ist der Namensraum der Systemvariablen. Eigene Variablen in Kleinbuchstaben, dann kann nichts kollidieren.

Was ich noch nicht verstehe ist der leere Delimiter oben (-d ''):

Code: Alles auswählen

read -d '' TIERE << EOF
    Esel
    Katze
    Elefant
    Hund
EOF
-d '' sorgt scheinbar dafuer, dass `read' nicht eine Zeile einliest, sondern alles. Das kannst du aber auch einfacher haben:

Code: Alles auswählen

tiere="Esel
Katze
Elefant
Hund"
(... wie du inzwischen ja schon selber rausgefunden hast.)

Ich möchte die Liste gerne oben separat haben, da ich diese ständig erweitern werde. (Hintergrund: Ich habe mir eine kleine CI-Pipeline aufgebaut, und ich möchte oben die einzelnen Skripts laufend ergänzen.)

Nachtrag: So geht es am einfachsten und ohne jegliche Bash-spezifischen Features:

Code: Alles auswählen

#!/bin/sh

TIERE="
    Esel
    Katze
    Elefant
    Hund
"

for TIER in $TIERE
do
    echo $TIER
done
Das geht so aber nur, wenn in jeder Zeile nur ein Wort steht, weil das wortweise und nicht zeilenweise arbeitet, wie die Umsetzung mit `read'.

Sonst z.B. so:

Code: Alles auswählen

#!/bin/sh

TIERE="
    Esel
    Katze
    Elefant
    Hund
"

echo "$TIERE" | while read TIER
do
    echo $TIER
done
Use ed once in a while!

JTH
Moderator
Beiträge: 3023
Registriert: 13.08.2008 17:01:41
Wohnort: Berlin

Re: bash: Liste mit read verarbeiten

Beitrag von JTH » 13.10.2019 21:47:59

Meillo hat geschrieben: ↑ zum Beitrag ↑
13.10.2019 20:36:40
Das ist oftmals eine Folge von Stackoverflow.
Oh ja.
Meillo hat geschrieben: ↑ zum Beitrag ↑
13.10.2019 21:42:12

Code: Alles auswählen

...
done <<!
$TIERE
!
Ich wollte gerade fragen, was „<<!“ für ein Konstrukt ist … :mrgreen: „!“ als heredoc-Begrenzung sieht man selten :wink:
Manchmal bekannt als Just (another) Terminal Hacker.

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

Re: bash: Liste mit read verarbeiten

Beitrag von Meillo » 13.10.2019 22:29:25

JTH hat geschrieben: ↑ zum Beitrag ↑
13.10.2019 21:47:59
Ich wollte gerade fragen, was „<<!“ für ein Konstrukt ist … :mrgreen: „!“ als heredoc-Begrenzung sieht man selten :wink:
Die meisten verwenden ``EOF''. Hab ich frueher auch gemacht ... bis ich irgendwo das Ausrufezeichen gesehen habe. Das hat mich sofort ueberzeugt. ;-)
Use ed once in a while!

Antworten