Zmiana kolejności wierszy pliku jak w innym pliku (Unix)

2

Czy istnieje narzędzie (lub opcja sort), które będą zmieniać kolejność wierszy pliku, aby były uporządkowane jak klucz w innym pliku?

Na przykład mam plik danych:

T01F01475558    30
T01F022B3A17    31
T01F022EEDFD    19
T01F026E0209    19

I inny (sortuj plik „klucza”):

T01F022EEDFD
T01F026E0209
T01F022B3A17
T01F01475558

Czy istnieje sposób na posortowanie pierwszego pliku, aby pierwsze pole było w tej samej kolejności co drugi plik? Każdy klucz jest unikalny (bez duplikatów), aw każdym pliku jest taka sama liczba linii.

Czy istnieje narzędzie UNIX, o którym nie wiem, które to zrobi?

Taj Morton
źródło

Odpowiedzi:

0

Każdy klucz jest unikalny (bez duplikatów), aw każdym pliku jest taka sama liczba linii.

To założenie jest bardzo ważne. Jeśli tak się stanie, to polecenie wykona zadanie (w Bash):

paste <(nl key.file | sort -k 2 | cut -f 1) <(sort data.file) | sort -n | cut -f 2-

Niewiele narzędzi używa znaków tabulacji jako separatorów. Z tego powodu zakładki nie mogą występować w key.file(mogą się jednak pojawić data.file). W key.filekażdym razie rozsądne wpisy powinny tworzyć jedną kolumnę, więc nie powinno to stanowić problemu.

Wyjaśnienie:

  1. nldodaje numer linii przed każdą linią key.file; powoduje to, że same klucze przechodzą do drugiej kolumny; sort -k 2sortuje według drugiej kolumny, tj. według kluczy. Klucze są następnie odrzucane przez cut -f 1.
  2. Inne sortrodzaje data.file. Ponieważ klucze z przodu są unikalne, to domyślne sortowanie jest równoważne sortowaniu według pojedynczych kluczy.
  3. Dwa wyniki z sort-s są scalane przez paste. Bez pierwszej cutprzykładowa linia brzmiałaby:

         4  T01F01475558    T01F01475558    30
    

    Kluczowa jest wyjątkowość kluczy i ich równa liczba w obu plikach. W efekcie te same klucze z obu sort-s spotykają się w tej samej linii, pozostawiając paste. Ponieważ nie potrzebujesz zduplikowanych kluczy do zajęcia pamięci, pierwszy z nich cutzostał użyty jak najszybciej. Dzięki temu prawdziwy przykład opuszczania linii pasteto:

         4  T01F01475558    30
    
  4. Linie te są następnie sortowane według ich wartości liczbowej. Numery linii od nlsą na początku, więc ta operacja wprowadza pożądaną kolejność.

  5. Na końcu cutodrzuca pierwszą kolumnę, pozostawiając dokładne wiersze z data.file, ale w pożądanej kolejności.

Możesz też spróbować tego (przetestowane w Bash):

while IFS='' read -r ; do
   [ -n "$REPLY" ] && grep "^$REPLY " data.file
done <key.file

Zauważ, że kod oczekuje spacji po każdym kluczu data.file.

Plusy:

  • key.filemoże określać dowolną liczbę kluczy, duplikaty kluczy, nieistniejących kluczy. W takim przypadku nie myśl „sortuj”, pomyśl „pobieranie po kolei pożądanych linii”.
  • Możesz przesyłać strumieniowo dane wejściowe (takie jak standardowe zamiast key.file, po prostu pomiń <key.file) i uzyskiwać dane wyjściowe w locie.

Cons:

  • grepzinterpretuje klucze jako wyrażenia regularne, może to się nie powieść. We wzorze jest grep -Fjednak ogólnie potrzebny ^.
  • readjest wolny; odradzanie grepsię jest powolne; data.filewielokrotne otwieranie jest powolne.
Kamil Maciorowski
źródło