Möglichkeit, Zeilenumbrüche (^ M) nur aus Variablen zu entfernen, nicht aus Dateien

8

Ich lade eine Datei in Variablen, das Problem ist, dass die Datei in Windows formatiert ist, glaube ich, so dass ich eine ^Manstelle einer neuen Zeile bekomme.

Wie ändere ich es, wenn sich der Wert in der Variablen befindet? Ich bin mir bewusst, dass ich die Quelle in VI ändern kann (ich verwende übrigens OS X), aber ich kann die Originaldatei nicht ändern, sondern nur lesen, daher muss ich die ^Maus der Variablen entfernen .

Nach meinem Verständnis \nist das nicht dasselbe wie ^M, daher trfunktioniert der Befehl nicht.

BEARBEITEN

Es scheint, dass die Frage nicht klar ist; Das ist also die Klarstellung.

Ich analysiere die Datei Zeile für Zeile; Jede Zeile hat 2 Werte, die durch Tabulatoren getrennt sind. Am Ende jeder Zeile befindet sich ein ^ M, es sieht folgendermaßen aus:

value1    value2^M
value3    value4^M
value5    value6^M
value7    value8^M

Mein Workflow ist ziemlich einfach und unkompliziert: Die txt-Datei enthält das, was Sie oben sehen, die Schleife separate Felder und für jede Zeile erhalten Sie die Werte; Wenn ich den zweiten Wert drucke, hat er das ^ M, das ich entfernen möchte

while IFS=$'\t' read -r -a line
do
    Type1="${line[0]}"
    Type2="${line[1]}"
done < $TXTFILE

Was bedeutet, dass es beim Drucken von Typ1 in Ordnung ist, aber die Variable Typ2 enthält das ^ M. Ich habe verwendet trund es hat nicht funktioniert, ich habe verwendet sed, um das letzte Zeichen der Variablen zu entfernen, und es hat nicht funktioniert. Hoffe das klärt meine Frage. Vielen Dank

Rataplan
quelle
1
Wie liest du die Datei in eine Variable? könnte möglich sein, es währenddessen zu entfernen ... zum Beispiel: Verwendung sed 's|\r||' fileanstelle vonfile
Sundeep
Ich wollte mit antworten, traber die Frage ist viel zu weit gefasst. Wir wissen nicht, wie die Eingabe oder Ausgabe ist oder wie das Skript aussieht.
Julie Pelletier
Ich habe der Frage weitere Informationen hinzugefügt. Ich lade die Datei mit der Standardschleife in Bash und ändere IFS in Tab, damit ich die Zeile in zwei Teile teilen und die beiden Variablen erhalten kann. Ich habe TR ausprobiert, aber es hat nicht funktioniert, genauso wie bei sed. Deshalb habe ich die Frage hier gestellt. Danke
rataplan
Ich finde es seltsam, dass Sie eine unnötig komplexe Lösung akzeptieren. Hast du meins probiert?
Jlliagre

Antworten:

9

^Mist ein Wagenrücklauf (CR), der wie \rfür troder innerhalb angegeben werden kann $'…'. \nGibt einen Zeilenvorschub (LF) an ^J. Ein Unix-Zeilenende ist LF, und ein Windows-Zeilentrennzeichen ist die zweistellige Folge CR-LF. Windows-Textdateien, die unter einem Unix-System wie Linux oder macOS angezeigt werden, sehen also so aus, als hätten sie ^Mam Ende jeder Zeile außer am letzten Zeile, die ihre letzte neue Zeile fehlt.

Sie können Wagenrückläufe aus einer Datei mit trmit entfernen

tr -d '\r' <somefile.txt >somefile.txt.new && mv somefile.txt.new somefile.txt

oder einfacher mit dos2unix.

Um zu vermeiden, dass die Dateien geändert werden, können Sie jede Zeile beim Lesen überprüfen und CR am Ende einer Zeile entfernen. Wenn Sie beispielsweise durch readTabulatoren getrennte Werte analysieren, entfernen Sie CR am Ende des letzten Felds. Die Parametererweiterung ${VAR%$'\r'}ergibt den Wert VARminus einer nachfolgenden CR und den Wert von, VARwenn sie nicht mit CR endet.

while IFS=$'\t' read -r -a line
do
    line[$((${#line[@]}-1))]="${line[$((${#line[@]}-1))]%$'\r'}"
    Type1="${line[0]}"
    Type2="${line[1]}"
done < "$TXTFILE"
Gilles 'SO - hör auf böse zu sein'
quelle
Vielen Dank für die Klarstellung, dass / r tatsächlich dasselbe ist wie ^ M; Die Lösung funktioniert
Rataplan
Beachten Sie, dass OS / X mit einer sehr alten Version von geliefert wird bash, daher erwarte ich nicht, dass es Unterstützung bietet, line[-1]für die Sie bash-4.3 oder höher benötigen. Es kommt mit, zshdass es unterstützt (und hat seit Jahrzehnten), aber beachten Sie, dass in zsh, das erste Element ist $line[1], nicht $line[0](außer in ksh Emulation). Mit älteren bashkönnen Sie immer verwendenline[${#line[@]}-1]
Stéphane Chazelas
+1 für die Hintergrunderklärung, aber ich denke, die Lösung von Jiliagre ist viel besser und viel einfacher.
Wildcard
7

Hier ist der einfachste Weg, um Ihr Skript zu reparieren. Fügen Sie einfach "Wagenrücklauf" als internes Feldtrennzeichen für den Lesebefehl hinzu:

während IFS = $ '\ t \ r ' -r -a Zeile liest
tun
  Typ1 = "$ {Zeile [0]}"
  Typ2 = "$ {Zeile [1]}"
erledigt <$ TXTFILE
jlliagre
quelle
1
@jiliagre, ja, du hast recht, es wird dort als Begrenzer genommen. Das wäre anders, zshwenn $IFSes als Trennzeichen verwendet wird.
Stéphane Chazelas
2
@ StéphaneChazelas Danke, Sie sind zu besessen von zsh;-)
jlliagre
4

Verwendung (für kurze Saiten):

${var//$'\015'}

Beispiel:

$ var=$'This is a test of a CR (\r) character'
$ echo "${var//$'\r'}"
This is a test of a CR () character

Für längere Saiten benötigen Sie möglicherweise sed oder awk.

Isaac
quelle
0

Eine allgemein nützlichere Methode zum Konvertieren des Inhalts von "DOS" -Dateien, die keine andere Inhaltsmarkierung als CR + LF-Zeilenenden haben (im Gegensatz zu nur Linux LF).

Für Ubuntu zuerst und nur einmal

sudo apt install dos2unix

die Verwendung wie unten angegeben, hier mit odzur Überprüfung der Ausgabe verwendet

$ dos2unix <$ TXTFILE | od -t x1z -w17
0000000 76 61 6c 75 65 31 20 20 20 20 76 61 6c 75 65 32 0a> Wert1 Wert2. <
0000021 76 61 6c 75 65 33 20 20 20 20 76 61 6c 75 65 34 0a> Wert3 Wert4. <
0000042 76 61 6c 75 65 35 20 20 20 20 76 61 6c 75 65 36 0a> Wert5 Wert6. <
0000063 76 61 6c 75 65 37 20 20 20 20 76 61 6c 75 65 38 0a> Wert7 Wert8. <
0000104

$ cat $ TXTFILE | od -t x1z -w18
0000000 76 61 6c 75 65 31 20 20 20 20 76 61 6c 75 65 32 0d 0a> Wert1 Wert2 .. <
0000022 76 61 6c 75 65 33 20 20 20 20 76 61 6c 75 65 34 0d 0a> Wert3 Wert4 .. <
0000044 76 61 6c 75 65 35 20 20 20 20 76 61 6c 75 65 36 0d 0a> Wert5 Wert6 .. <
0000066 76 61 6c 75 65 37 20 20 20 20 76 61 6c 75 65 38 0d 0a> Wert7 Wert8 .. <
0000110

Dies übersetzt nicht nur die Zeilenenden, sondern auch andere Sonderzeichen, abhängig von den Parametern dos2unixoder dem Gegenstück unix2dos(das gleichzeitig installiert wird).

Hannu
quelle
ist dos2unix nicht standardmäßig da?
Phuclv
Ich habe klar angegeben, dass ich weiß, wie es durch Dateimodifikation gemacht wird. Außerdem verwende ich nicht Linux, sondern OSX. Um dos2unix zu installieren, muss ich
Brew
dos2unixist nicht auf die Verwendung der FILE-Modifikation festgelegt, sondern "ein Filter" und kann in Pipes verwendet werden. genau wie tr. Es sollte auch vorgezogen werden, trda es Zeichensätze auf einer höheren Ebene verarbeitet, nicht nur Einzelbyte-Codes.
Hannu
@ Lưu Vĩnh Phúc, ich verwende Ubuntu 16.04 und habe eine ziemlich neue Installation, und ich musste sie installieren.
Hannu