Bash Lesen Sie ignoriert führende Leerzeichen
Habe ich die Datei a.txt
mit folgendem Inhalt
aaa
bbb
Wenn ich führen Sie die folgenden Skripts:
while read line
do
echo $line
done < a.txt > b.txt
generiert b.txt
enthält folgende
aaa
bbb
Es ist ersichtlich, dass die führenden Leerzeichen von Zeilen wurden entfernt. Wie kann ich beibehalten führende Leerzeichen?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist in der Bash-FAQ-Eintrag auf die Daten Lesen, line-by-line.
Als Charles Duffy richtig darauf hin (und ich es vermisst hatte durch die Konzentration auf die
IFS
Problem); wenn Sie möchten, um zu sehen, die Leerzeichen in der Ausgabe, die Sie auch brauchen, um die Angabe der variable, wenn Sie es verwenden, oder die shell, mal wieder, löschen Sie die Leerzeichen.Notizen über einige andere Unterschiede, die zitiert snippet als im Vergleich zu Ihrem ursprünglichen code.
Den Einsatz der
-r
argumentread
bedeckt ist, in einem einzigen Satz am oberen Rand der zuvor verlinkten Seite.Mit
printf
stattecho
es, das Verhalten derecho
ist, etwas leider nicht tragbar konsistent in allen Umgebungen und die Unterschiede können schwierig sein zu behandeln.printf
auf der anderen Seite ist konsistent und verwendet werden können völlig robust.read
alle Argumente zu verwenden, um halten Sie die Eingabe (Berufung auf die Standard-variableREPLY
), keine whitespace-Zeichen entfernt und man weglassen können, die änderungIFS
. Das istwhile read -r; do printf '%s\n' "$REPLY"; done < "$file"
IFS
. (Vorausgesetzt, dass Sie akzeptieren, dass die Aufteilung einer Zeile in einem Feld ist immer noch eine geteilte, wenn auch ein degenerierter ein.) In jedem Fall ist es einbash
ism; POSIXread
erfordert mindestens ein argument.$REPLY
(Hervorhebung von mir): "Legen Sie auf den Linie Eingabe Lesen der read-builtin-Befehl, wenn keine Argumente geliefert werden." Also, die Idee ist, Lesen Sie die ganze Zeile ist im Gegensatz zu Aufteilung in Felder. Was ist counter-intuitiv, ist jedoch, dass Sie noch zusätzlich angeben-r
zu vermeiden backslash-interpretation. Beachten Sie, dass die (selten verwendet)select
konstruieren, wo die Aufteilung in Felder, die gar nicht ins Bild - auch sets$REPLY
zu, was der Benutzer eingegeben (immer backslash interpretiert, aber sonst auch so ist).-r
ist immer noch notwendig, zu unterdrücken backslash-interpretation, auch wenn Sie mit nur$REPLY
(keine Angabe von Variablennamen): Keine Angabe-r
möglicherweise liest mehrere Zeilen auf einmal (kam ohne Zeilenumbrüche), wenn die Eingabe\
-maskierten newlines; wenn mit nur$REPLY
implizite-r
diese multi-line-Verhalten würde nicht zur Verfügung stehen.-r
und-r
-für-Zeilenumbrüche-nur.read
's Standard-Verhalten lässt zeilenfortsetzung vom Ende einer Zeile mit\
- und Weiterbildung es in der nächsten Zeile (sowohl die\
- und newline sind verworfen). Dies ist selten sinnvoll, außer vielleicht für interaktiven Eingabe, und, gegeben, dass die\
in irgendeinem\<char>
- pair-Mädchen wird verworfen, in der Regel überrascht den Benutzer. Ich denke, das eigentliche Problem hier ist, dass das Verhalten-r
(immer Lesen einzige - Zeile, halten alle backslashes) sollte die Standard Verhalten alle zusammen, aber das derzeitige Verhalten ist mit POSIX vorgeschrieben, also sind wir dabei geblieben. (Fortsetzung im nächsten Kommentar)-r
, und ich sehe nicht ein echtes Bedürfnis zu unterstützen zeilenfortsetzung mit-r
. Zwar nicht ganz das gleiche, wenn Sie das Bedürfnis haben, Lesen Sie auf Zeilen inbash
,ksh
, undzsh
verwenden, können Sieread -r d <delimChar> …
, der hat den Vorteil, dass die Zeilenumbrüche nicht (und sollte nicht)\
-entkommen.Gibt es mehrere Probleme:
IFS
deaktiviert ist,read
Streifen führende und nachfolgende Leerzeichen.echo $line
string-splits und glob-erweitert den Inhalt$line
, brechen Sie in einzelne Worte und übergeben diese Worte als einzelne Argumente an dieecho
Befehl. So, auch mit IFS gelöschtread
Zeitecho $line
würde noch verwerfen führende und nachfolgende Leerzeichen, und ändern Sie läuft von Leerzeichen zwischen den Wörtern in ein einzelnes Leerzeichen ein jeder. Zusätzlich eine Zeile mit nur den Charakter*
würde erweitert werden, um enthalten eine Liste von Dateinamen.echo "$line"
ist eine deutliche Verbesserung, aber immer noch nicht richtig verarbeiten Werte wie-n
, die es behandelt, als echo argument selbst.printf '%s\n' "$line"
würde dieses Problem beheben voll.read
ohne-r
behandelt backslashes als Fortsetzung-Zeichen anstelle von literalen Inhalt, so dass Sie nicht in der erzeugten Werte, es sei denn, verdoppelt-bis zu Flucht selbst.Also:
\n
macht nicht Ergebnis in eine Zeilenumbruch, führt in Literalen
. Durch Kontrast, eine\
-Escape - ist newline Ursachenread
zu Lesen, die folgende - Zeile auch, und direkt hängen Sie an den aktuellen (verwerfen der\
- und newline). Ein\
vor allen anderen Zeichen einfach verworfen.read
ohne-r
: die Eingabe wird geparst, in der gleichen Weise ein bareword mit individuell\
-Escape-Zeichen wird analysiert, indem die (POSIX) shell selbst (z.B. als Teil einer argument-Liste), wie beschrieben unter pubs.opengroup.org/onlinepubs/9699919799/utilities/... und im wesentlichen dupliziert inread
's POSIX-Spezifikation in pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html.