Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
-
ren22
Beitrag
von ren22 » 19.02.2018 15:35:49
Hallo,
ich versuche gerade ein String "hallo - welt" in einzelne Buchstaben zu zerlegen, leider scheitert es an der Ausgabe bei Leerfeldern.
Code: Alles auswählen
string="hallo - welt"
for i in $( echo $string| grep -o .); do
echo "akueller Buchstabe ist: $i"
done
Ausgabe:
Code: Alles auswählen
akueller Buchstabe ist: h
akueller Buchstabe ist: a
akueller Buchstabe ist: l
akueller Buchstabe ist: l
akueller Buchstabe ist: o
akueller Buchstabe ist: -
akueller Buchstabe ist: w
akueller Buchstabe ist: e
akueller Buchstabe ist: l
akueller Buchstabe ist: t
warum werden leerfelder nicht ausgeben?
Zuletzt geändert von ren22 am 19.02.2018 16:28:50, insgesamt 2-mal geändert.
-
MSfree
- Beiträge: 11617
- Registriert: 25.09.2007 19:59:30
Beitrag
von MSfree » 19.02.2018 16:03:28
Very quick and very dirty
Code: Alles auswählen
#!/bin/bash
string="hallo - welt"
number=0
letter=${string:$number:1}
until test -z "$letter"
do
echo $letter
number=$number+1
letter=${string:$number:1}
done
-
uname
- Beiträge: 12412
- Registriert: 03.06.2008 09:33:02
Beitrag
von uname » 19.02.2018 16:04:57
Vielleicht so:
Code: Alles auswählen
string="hallo - welt";for i in $(seq 1 ${#string});do echo "akueller Buchstabe ist:" ${string:var=$((i-1)):1};done
Oder besser mit awk:
Code: Alles auswählen
string="hallo - welt";echo $string | awk 'BEGIN{FS=""}{for(i=1;i<=NF;i++)print "akueller Buchstabe ist: "$(i)}'
ren22 hat geschrieben:warum werden leerfelder nicht ausgeben?
Weil "echo $string" den String in drei Stücke zerlegt und die Leerzeichen entfernt.
-
hikaru
- Moderator
- Beiträge: 13914
- Registriert: 09.04.2008 12:48:59
Beitrag
von hikaru » 19.02.2018 16:27:06
uname hat geschrieben: 19.02.2018 16:04:57
ren22 hat geschrieben:warum werden leerfelder nicht ausgeben?
Weil "echo $string" den String in drei Stücke zerlegt und die Leerzeichen entfernt.
Jein. Wenn
echo hier der Übeltäter wäre, dann würde es ausreichen, $string zu quoten damit wirklich die gesamte Zeile als ein String behandelt wird:
echo "$string"
Genau genommen zerlegt nicht echo den String, sondern die for-Schleife, denn Leerzeichen (Whitespaces?) sind standardmäßig die "internal field seperators" (IFS) in bash.
Der ursprüngliche Code funktioniert daher, wenn man einfach den IFS neu definiert:
Code: Alles auswählen
IFS=$'\n'
string="hallo - welt"
for i in $( echo $string| grep -o .); do
echo "akueller Buchstabe ist: $i"
done
-
ren22
Beitrag
von ren22 » 19.02.2018 16:28:13
-
ren22
Beitrag
von ren22 » 19.02.2018 16:38:40
wenn ich den/die "IFS" "internal field seperators" vor der for Schleife schreibe
und noch weiteren code in dem bashscript habe, greift dann IFS auch auf den rest des codes zu ? und wenn ja wie beendet man das IFS wieder nach der for schleife, damit keine Fehler im rest des Codes auftreten.
-
hikaru
- Moderator
- Beiträge: 13914
- Registriert: 09.04.2008 12:48:59
Beitrag
von hikaru » 19.02.2018 16:50:37
Der geänderte IFS gilt ab dem Punkt der Änderung für die gesamte Shell (in dem Fall also für das komplette Script).
Falls du später im Code wieder den Standard-IFS haben willst, dann kannst du ihn auch wieder zurücksetzen:
Das ist zwar wenig Schreibarbeit, aber es erscheint mir konzeptuell unschön, eigentlich als Umgebungsvariablen gedachte Schalter in einem Script mehrfach an- und auszuknipsen, damit der Code läuft. In dem Fall würde ich dann doch eine andere Lösung bevorzugen.
-
ren22
Beitrag
von ren22 » 19.02.2018 16:54:24
Code: Alles auswählen
IFS=$'\n'
string="hallo - welt"
for i in $( echo $string| grep -o .); do
echo "akueller Buchstabe ist: $i"
done
unset IFS
also, sollte dann der rest in dem script von den obrigen Zeilen nicht beeinflusst werden ?
-
tobo
- Beiträge: 2367
- Registriert: 10.12.2008 10:51:41
Beitrag
von tobo » 19.02.2018 17:17:33
Doch, bei einem unset ist die Variable weg. Entweder speicherst du dir den IFS und setzt ihn danach wieder auf den alten Wert:
oder lässt das alles unberührt und quotest die For-Schleife:
-
uname
- Beiträge: 12412
- Registriert: 03.06.2008 09:33:02
Beitrag
von uname » 19.02.2018 19:46:21
Danke. Auch wieder was gelernt.
-
hikaru
- Moderator
- Beiträge: 13914
- Registriert: 09.04.2008 12:48:59
Beitrag
von hikaru » 19.02.2018 21:08:03
tobo hat geschrieben: 19.02.2018 17:17:33
oder lässt das alles unberührt und quotest die For-Schleife:
Ich verstehe noch nicht ganz was hier passiert, aber offenbar wird die Schleife nur einmal durchlaufen, gibt in diesem einen Durchlauf aber trotzdem alle Buchstaben aus. Das wird deutlich, wenn man wie ren22 einen fixen String mit ausgibt:
Code: Alles auswählen
string="hallo - welt"
for i in "$( echo $string| grep -o .)"; do
echo "akueller Buchstabe ist: $i"
done
erzeugt:
Code: Alles auswählen
$ bash test.sh
akueller Buchstabe ist: h
a
l
l
o
-
w
e
l
t
-
RobertDebiannutzer
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Beitrag
von RobertDebiannutzer » 19.02.2018 21:45:23
Wie wär's mit
Code: Alles auswählen
sed 's/./Aktueller\ Buchstabe ist:\ &\n/g' <<< "$INPUT"
(für INPUT="Hallo - Welt")
Ergibt:
Code: Alles auswählen
Aktueller Buchstabe ist: H
Aktueller Buchstabe ist: a
Aktueller Buchstabe ist: l
Aktueller Buchstabe ist: l
Aktueller Buchstabe ist: o
Aktueller Buchstabe ist:
Aktueller Buchstabe ist: -
Aktueller Buchstabe ist:
Aktueller Buchstabe ist: W
Aktueller Buchstabe ist: e
Aktueller Buchstabe ist: l
Aktueller Buchstabe ist: t
Wenn Leerzeile am Schluss stört, kann man die ja noch entfernen mit einem Umweg über printf oder irgendeinem sed-Trick.
-
tobo
- Beiträge: 2367
- Registriert: 10.12.2008 10:51:41
Beitrag
von tobo » 19.02.2018 22:06:55
hikaru hat geschrieben: 19.02.2018 21:08:03
Ich verstehe noch nicht ganz was hier passiert, aber offenbar wird die Schleife nur einmal durchlaufen, gibt in diesem einen Durchlauf aber trotzdem alle Buchstaben aus. Das wird deutlich, wenn man wie ren22 einen fixen String mit ausgibt:
Das stimmt natürlich. Es wird nur ein Argument übergeben, weshalb i nach einem Schleifendurchlauf schon fertig befüllt ist, jeweils getrennt durch \n. Das war also offensichtlich ein Schnellschuss - so geht's nicht.
-
owl102
Beitrag
von owl102 » 19.02.2018 22:54:33
tobo hat geschrieben: 19.02.2018 17:17:33
Entweder speicherst du dir den IFS und setzt ihn danach wieder auf den alten Wert:
Das geht aber nicht so einfach, da
IFS nicht gesetzt und
IFS="" unterschiedliche Auswirkungen haben. Nach deinem Code wird aber aus
IFS nicht gesetzt zu
IFS="".
Hier wäre zum Beispiel ein Code, der das berücksichtigt:
https://unix.stackexchange.com/a/264947/167017
Am einfachsten löst man aber solche Probleme, indem man den Code (wenn möglich) in eine Subshell () packt, dann restauriert sich IFS am Ende automatisch.
Davon ab biete ich die 73ste Lösungs-Variante für das gestellte Problem:
Code: Alles auswählen
#!/bin/bash
string="hallo - welt"
while [[ $string ]]
do
printf "Aktueller Buchstabe ist: %s\n" "${string:0:1}"
string=${string:1}
done
Zuletzt geändert von owl102 am 20.02.2018 10:32:09, insgesamt 1-mal geändert.
-
tobo
- Beiträge: 2367
- Registriert: 10.12.2008 10:51:41
Beitrag
von tobo » 20.02.2018 00:24:49
owl102 hat geschrieben: 19.02.2018 22:54:33
Das geht aber nicht so einfach, da
IFS nicht gesetzt und
IFS="" unterschiedliche Auswirkungen haben. Nach deinem Code wird aber aus
IFS nicht gesetzt zu
IFS="".
Stimmt, für den Fall das IFS initial nicht existiert ist so eine Rückzuweisung falsch. Das hatte ich so noch gar nicht auf dem Schirm - vielen Dank!