Mit sed
Verwenden Sie sed mit den verschachtelten Unterausdrücken grundlegender regulärer Ausdrücke, um den Spalteninhalt zu erfassen und neu zu ordnen. Dieser Ansatz eignet sich am besten, wenn wie in diesem Fall nur eine begrenzte Anzahl von Schnitten zum Neuordnen von Spalten vorhanden ist.
Die Grundidee besteht darin, interessante Teile des Suchmusters mit \(
und zu umgeben \)
, die im Ersatzmuster wiedergegeben werden können, wobei \#
wobei #
die sequentielle Position des Unterausdrucks im Suchmuster dargestellt wird.
Beispielsweise:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
Ausbeuten:
bar foo
Text außerhalb eines Unterausdrucks wird gescannt, aber nicht für die Wiedergabe in der Ersatzzeichenfolge beibehalten.
Obwohl in der Frage keine Spalten mit fester Breite erörtert wurden, werden wir hier darauf eingehen, da dies ein würdiges Maß für jede gestellte Lösung ist. Nehmen wir der Einfachheit halber an, dass die Datei durch Leerzeichen getrennt ist, obwohl die Lösung für andere Trennzeichen erweitert werden kann.
Reduzierende Räume
Um die einfachste Verwendung zu veranschaulichen, nehmen wir an, dass mehrere Leerzeichen zu einzelnen Leerzeichen zusammengefasst werden können und die Werte der zweiten Spalte mit EOL (und nicht mit Leerzeichen aufgefüllt) abgeschlossen werden.
Datei:
bash-3.2$ cat f
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 nl
0000040 s t r 2 sp sp sp sp sp sp sp 2 nl s t r
0000060 3 sp sp sp sp sp sp sp 3 nl
0000072
Verwandeln:
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)[ ]*\([^ ]*\)[ ]*/\2 \1/" f | od -a
0000000 C o l u m n 2 sp C o l u m n 1 nl
0000020 1 sp s t r 1 nl 2 sp s t r 2 nl 3 sp
0000040 s t r 3 nl
0000045
Spaltenbreiten erhalten
Erweitern wir die Methode nun auf eine Datei mit Spalten konstanter Breite, während Spalten unterschiedliche Breiten haben können.
Datei:
bash-3.2$ cat f2
Column1 Column2
str1 1
str2 2
str3 3
bash-3.2$ od -a f2
0000000 C o l u m n 1 sp sp sp sp C o l u m
0000020 n 2 nl s t r 1 sp sp sp sp sp sp sp 1 sp
0000040 sp sp sp sp sp nl s t r 2 sp sp sp sp sp sp
0000060 sp 2 sp sp sp sp sp sp nl s t r 3 sp sp sp
0000100 sp sp sp sp 3 sp sp sp sp sp sp nl
0000114
Verwandeln:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2
Column2 Column1
1 str1
2 str2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f2 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r 2 sp sp sp sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Obwohl das Beispiel der Frage keine ungleich langen Zeichenfolgen enthält, unterstützt dieser sed-Ausdruck diesen Fall.
Datei:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Verwandeln:
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3
Column2 Column1
1 str1
2 string2
3 str3
bash-3.2$ sed "s/\([^ ]*\)\([ ]*\) \([^ ]*\)\([ ]*\)/\3\4 \1\2/" f3 | od -a
0000000 C o l u m n 2 sp C o l u m n 1 sp
0000020 sp sp nl 1 sp sp sp sp sp sp sp s t r 1 sp
0000040 sp sp sp sp sp nl 2 sp sp sp sp sp sp sp s t
0000060 r i n g 2 sp sp sp nl 3 sp sp sp sp sp sp
0000100 sp s t r 3 sp sp sp sp sp sp nl
0000114
Vergleich mit anderen Methoden der Spaltenumordnung unter der Schale
Überraschenderweise eignet sich awk für ein Dateimanipulationswerkzeug nicht zum Schneiden von einem Feld bis zum Ende der Aufzeichnung. In sed kann dies mit regulären Ausdrücken erreicht werden, z. B. \(xxx.*$\)
wo xxx
ist der Ausdruck, der mit der Spalte übereinstimmt.
Das Verwenden von Einfügen und Ausschneiden von Subshells wird bei der Implementierung in Shell-Skripten schwierig. Code, der über die Befehlszeile funktioniert, kann nicht analysiert werden, wenn er in ein Shell-Skript eingefügt wird. Zumindest war dies meine Erfahrung (die mich zu diesem Ansatz geführt hat).
cut
dass dieser intuitive Befehl zum Nachbestellen nicht unterstützt wird. Ein weiterer Tipp: Sie könnenawk
's-FS
und-OFS
Optionen verwenden, um benutzerdefinierte Eingabe- und Ausgabefeldtrennzeichen (wie-d
und--output-delimiter
fürcut
) zu verwenden.