2013-06-06 17 views
7

Chcę posortować plik na wielu polach i kilku separatorach pól. Proszę pomóż. Oto mój przykładowy plik danych:Jak sortować na wielu polach z innym separatorem pól?

$ cat Data3 
My Text|50002/100/43 
My Message|50001/100/7 
Help Text|50001/100/7 
Help Message|50002/100/11 
Text Message|50001/100/63 
Visible Text|50001/100/52 
Invisible Text|50002/100/1 

Pierwszy separator pól jest symbolem rura i drugi separator pole jest /. Chcę najpierw posortować te dane na drugim polu, a następnie dane powinny być posortowane według ostatniego pola (oddzielone przez /). Wreszcie moje posortowane dane powinny wyglądać następująco:

Help Text|50001/100/7 
My Message|50001/100/7 
Visible Text|50001/100/52 
Text Message|50001/100/63 
Invisible Text|50002/100/1 
Help Message|50002/100/11 
My Text|50002/100/43 

Korzystając sort -k2,2n -t'|', jestem w stanie rozwiązać na polu 2 (50001/50002), ale potem w ciągu tej wartości w jaki sposób można sortować na ostatnim polu (oddzielone /) ?

+0

Co rurociągów swój wynik i za pomocą 'sort' ponownie? – fedorqui

Odpowiedz

2

Można użyć tego (nieefektywne, ale proste) skrypt:

#!/usr/bin/perl 
print sort { @ka = split ?[|/]?, $a; 
       @kb = split ?[|/]?, $b; 
       $ka[1] <=> $kb[1] 
      || $ka[3] <=> $kb[3] 
      || $ka[0] cmp $kb[0] 
      } <> 

Można pominąć linię || $ka[0] cmp $kb[0] jeśli nie obchodzi dla linii o równej wartości mają być sortowane przez SMS.

+0

Jeśli to nieskuteczne, dlaczego warto to zaproponować? – Stephan

+4

Ponieważ algorytmiczne, wydajność obliczeniowa (co tutaj jest znaczone) nie zawsze jest oczywiście głównym celem. – Armali

9

Najprostszą sztuczką dla tego zestawu danych jest traktowanie drugiej kolumny jako numeru wersji.

$ cat Data3 | sort -k2,2V -t'|' 
Help Text|50001/100/7 
My Message|50001/100/7 
Visible Text|50001/100/52 
Text Message|50001/100/63 
Invisible Text|50002/100/1 
Help Message|50002/100/11 
My Text|50002/100/43 

Jednak to nie zawsze działa w zależności od danych wejściowych. To zadziała, ponieważ wartości w drugiej kolumnie są takie same.

Możesz zrobić to, co zaproponował fedorqui i uruchomić sortowanie dwa razy, a drugi raz zrobić stabilny sort. Ze strony podręcznika: -s, --stable (ustabilizuj sort, wyłączając porównanie ostatniego testu).

Pierwszy sort według kryteriów sortowania wtórnego. Następnie wykonaj sortowanie stabilne, zachowując kolejność sortowania w wierszach, które mają wspólny klucz z podstawowych kryteriów sortowania.

$ cat Data3 | sort -k3,3n -t'/' | sort -k2,2n -t'|' -s 
Help Text|50001/100/7 
My Message|50001/100/7 
Visible Text|50001/100/52 
Text Message|50001/100/63 
Invisible Text|50002/100/1 
Help Message|50002/100/11 
My Text|50002/100/43 

Masz trochę szczęścia w tym przypadku, ponieważ -k2,2n -t ​​'|' będzie traktować drugą kolumnę "50001/100/7" jako liczbę, która prawdopodobnie będzie równa 50001. Możesz skończyć się dziwnymi sytuacjami, jeśli będzie to oddzielane przecinkami zamiast ukośnika i używasz różnych ustawień narodowych w swoim środowisku. Na przykład, domyślnie w moim środowisku uruchamiam en_US.UTF-8, który zachowuje się w ten sposób.

$ cat Data3 | tr '/' ',' | sort -k3,3n -t',' | LC_NUMERIC=en_US.UTF-8 sort -k2,2n -t'|' -s 
Help Text|50001,100,7 
My Message|50001,100,7 
Invisible Text|50002,100,1 
Visible Text|50001,100,52 
Text Message|50001,100,63 
Help Message|50002,100,11 
My Text|50002,100,43 

Czego można oczekiwać to:

$ cat Data3 | tr '/' ',' | sort -k3,3n -t',' | LC_NUMERIC=C sort -k2,2n -t'|' -s 
Help Text|50001,100,7 
My Message|50001,100,7 
Visible Text|50001,100,52 
Text Message|50001,100,63 
Invisible Text|50002,100,1 
Help Message|50002,100,11 
My Text|50002,100,43 
4

Poniższy kod działa na mnie tak długo, jak nie ma żadnych dodatkowych '|' znaków w tekście.

tr '|' '/' | sort -n -t '/' -k3 -k4 | sed -re 's/^([^/]*)\/(.*)$/\1|\2/'

1

mały trick z awk

$ cat Data3 | awk -F'[|/]' '{print $2"\t"$4"\t"$0}' | sort -k1 -k2 -n | cut -f3- 
Help Text|50001/100/7 
My Message|50001/100/7 
Visible Text|50001/100/52 
Text Message|50001/100/63 
Invisible Text|50002/100/1 
Help Message|50002/100/11 
My Text|50002/100/43 
  • można użyć awk ze wszystkimi separatorów -F'[|/]' określonych drukować kluczy sortowania pierwszy $2"\t"$4 a następnie wydrukować linii wejściowej $0
  • następnie zrobić jeden sort z wieloma kluczami -k1 -k2 (uwaga: nie s ame jak -k1,2)
  • następnie cut z powrotem do linii wejściowej

uniwersalne dla wielu scenariuszy

Powiązane problemy