Korzystanie z sed
Użyj seda z zagnieżdżonymi podwyrażeniami podstawowych wyrażeń regularnych, aby przechwycić i zmienić kolejność zawartości kolumny. To podejście najlepiej sprawdza się, gdy istnieje ograniczona liczba cięć w celu zmiany kolejności kolumn, jak w tym przypadku.
Podstawową ideą jest otoczenie interesujących części wzorca wyszukiwania znakami \(
i \)
, które mogą być odtwarzane we wzorcu zastępczym, \#
gdzie gdzie #
oznacza sekwencyjną pozycję wyrażenia podrzędnego we wzorcu wyszukiwania.
Na przykład:
$ echo "foo bar" | sed "s/\(foo\) \(bar\)/\2 \1/"
plony:
bar foo
Tekst poza podwyrażeniem jest skanowany, ale nie jest zachowywany do odtworzenia w ciągu zastępczym.
Chociaż pytanie nie dotyczyło kolumn o stałej szerokości, omówimy je tutaj, ponieważ jest to godna miara każdego przedstawionego rozwiązania. Dla uproszczenia załóżmy, że plik jest rozdzielany spacjami, chociaż rozwiązanie można rozszerzyć o inne separatory.
Zapadające się spacje
Aby zilustrować najprostsze użycie, załóżmy, że wiele spacji można zwinąć do pojedynczych spacji, a wartości drugiej kolumny są zakończone znakiem EOL (a nie spacjami).
Plik:
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
Przekształcać:
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
Zachowywanie szerokości kolumn
Rozszerzmy teraz tę metodę do pliku z kolumnami o stałej szerokości, jednocześnie zezwalając na różne szerokości kolumn.
Plik:
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
Przekształcać:
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
Wreszcie, chociaż przykład pytania nie zawiera łańcuchów o nierównej długości, to wyrażenie sed potwierdza ten przypadek.
Plik:
bash-3.2$ cat f3
Column1 Column2
str1 1
string2 2
str3 3
Przekształcać:
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
Porównanie z innymi metodami zmiany kolejności kolumn pod powłoką
Co zaskakujące, jak na narzędzie do manipulacji plikami, awk nie nadaje się dobrze do wycinania od pola do końca rekordu. W sed można to osiągnąć za pomocą wyrażeń regularnych, np. \(xxx.*$\)
Gdzie xxx
jest wyrażenie pasujące do kolumny.
Używanie podpowłok wklejania i wycinania jest trudne podczas implementacji wewnątrz skryptów powłoki. Kod działający z wiersza poleceń nie jest analizowany po przeniesieniu do skryptu powłoki. Przynajmniej takie było moje doświadczenie (które skłoniło mnie do takiego podejścia).
cut
że nie obsługuje tego intuicyjnego polecenia zmiany kolejności. Tak czy inaczej, kolejna wskazówka: można użyćawk
„s-FS
oraz-OFS
opcje użycie niestandardowego wejścia i wyjścia (separatory polowych jak-d
i--output-delimiter
dlacut
).