ubuntuusers.de

Datei Zeilenweise einlesen mit Whitespace

Status: Gelöst | Ubuntu-Version: Ubuntu 12.10 (Quantal Quetzal)
Antworten |

coro

Anmeldungsdatum:
22. Januar 2008

Beiträge: 30

Ich habe eine Datei mit folgendem Inhalt,

$ cat txt
John
     Wayne
Starsky \
Hutch

Mein Problem ist das wenn ich die Datei 'txt' mit einer 'while' Schleife an 'read' übergebe Leerzeichen ignoriert werden. Ich konnte in der man page zu 'read' lediglich die Option '-r' finden, welche zumindest den backslash ignoriert.

while read -r line ;do
   printf "%s\n" "$line"; done < txt

## Ausgabe
John
Wayne
Starsky \
Hutch

Ich habe mit 'sed' eine Lösung konstruieren können, welche die Problematik behebt, allerdings nicht mit der Geschwindigkeit der oben beschriebenen Lösung.

for line in $(seq $(wc -l txt |awk '{print $1}')) ;do 
   sed -n ''$line'p' txt ;done

## Ausgabe
John
     Wayne
Starsky \
Hutch

Wenn jemand mir eine bessere Lösung anbieten kann wäre ich sehr dankbar.

Vain

Avatar von Vain

Anmeldungsdatum:
12. April 2008

Beiträge: 2510

Servus,

das Problem sind die Delimiter in „$IFS“, anhand derer die gelesene Zeile in Worte aufgetrennt wird. Das findet leider auch statt, wenn du hinten nur eine Variable angibst. Die allgemeine Form ist ja „read [optionen] var1 var2 var3 ... varN“, wobei die gelesene Zeile aufgetrennt wird und die einzelnen Worte den Variablen zugewiesen werden. Der Knackpunkt ist, dass die letzte Variable alle restlichen Worte zugewiesen bekommt – und nicht die ursprüngliche Zeile.

Du hast zwei Möglichkeiten, das zu umgehen:

Temporäres Umbelegen von „$IFS“ – hässlichere Lösung, aber wer weiß, wozu es gut ist:

$ while IFS=$'\n' read -r line; do echo "'$line'"; done < data
'John'
'     Wayne'
'Starsky \'
'Hutch'

Weglassen des Variablennamens und Verwendung von „$REPLY“ – finde ich schöner:

$ while read -r; do echo "'$REPLY'"; done < data
'John'
'     Wayne'
'Starsky \'
'Hutch'

coro

(Themenstarter)

Anmeldungsdatum:
22. Januar 2008

Beiträge: 30

Vielen Dank für die schnelle Lösung.

Die 'IFS' Variable zu manipulieren wird durch deinen zweiten Vorschlag fast obsolet, da ich mir auch die Zeile für das Zurücksetzen dieser Variable sparen kann.

Ich wundere mich das ich in der man page zu 'read' nichts über die Variable 'REPLY' finden konnte, allerdings unter 'man bash' folgendes finde

REPLY Set  to  the line of input read by the read builtin command when
      no arguments are supplied.

Interresant,

Vain you made my day

Vain

Avatar von Vain

Anmeldungsdatum:
12. April 2008

Beiträge: 2510

coro schrieb:

Ich wundere mich das ich in der man page zu 'read' nichts über die Variable 'REPLY' finden konnte, allerdings unter 'man bash' folgendes finde

Achso, ich bin jetzt blind davon ausgegangen, dass es sich um die Bash handelt. Mir ist’s auch in deinem ersten Posting nicht aufgefallen, dass du bei „man read“ nachgeschaut hast. Dieses „$REPLY“ ist eine Bash-Erweiterung, die es in POSIX-Shells nicht gibt. Das „man read“ zeigt dir aber die Information zu POSIX an, wie du im Header und Prolog sehen kannst.

Das heißt, solltest du die Dash verwenden wollen/müssen, dann musst du das mit „$IFS“ machen. Aber in einer leichten Variation:

$ while IFS='
' read -r line; do echo "'$line'"; done < data
'John'
'     Wayne'
'Starsky \'
'Hutch'

Das

IFS='
'

ist Absicht, damit genau ein Newline-Zeichen darin steht. Du brauchst die Variable auch nicht zurücksetzen, die gilt nur für „read“ – und weder im Schleifenrumpf noch nach Ende der Schleife.

coro

(Themenstarter)

Anmeldungsdatum:
22. Januar 2008

Beiträge: 30

Ok es klingelt ☺

Nochmals vielen dank für die Erläuterung

Antworten |