2013-03-02 16 views
10

Załóżmy, że mam dwa pliki, en.csv i sp.csv, każda zawierająca dokładnie dwa oddzielone przecinkami zapisów:Jak uzyskać dostęp do wszystkich pól w łączeniu zewnętrznym przy dołączaniu do systemu Unix?

en.csv:

1,dog,red,car 
3,cat,white,boat 

sp.csv:

2,conejo,gris,tren 
3,gato,blanco,bote 

Jeśli wykonam

join -t, -a 1 -a 2 -e MISSING en.csv sp.csv 

wyjście pojawia się:

1,dog,red,car 
2,conejo,gris,tren 
3,cat,white,boat,gato,blanco,bote 

Zauważ, że wszystkie brakujące pola zostały zwinięte. Aby uzyskać "właściwe" pełne sprzężenie zewnętrzne, muszę określić format; zatem

join -t, -a 1 -a 2 -e MISSING -o 0,1.2,1.3,1.4,2.2,2.3,2.4 en.csv sp.csv 

daje

1,dog,red,car,MISSING,MISSING,MISSING 
2,MISSING,MISSING,MISSING,conejo,gris,tren 
3,cat,white,boat,gato,blanco,bote 

Wadą tego sposobu uzyskania pełnego sprzężenia zewnętrznego jest to, że trzeba wyraźnie określić format końcowej tabeli, które nie mogą być łatwe do zrobienia w programowym aplikacje (gdzie tożsamość połączonych tabel jest znana tylko w czasie wykonywania).

Najnowsze wersje GNU join eliminują ten brak, wspierając specjalny format auto. Dlatego z taką wersją join ostatnie polecenie powyżej może być zastąpiony przez znacznie bardziej ogólny

join -t, -a 1 -a 2 -e MISSING -o auto en.csv sp.csv 

jaki sposób można osiągnąć ten sam efekt z wersjami join które nie obsługują opcję -o auto?


i dane szczegółowe

że posiada powłokę, (zsh) scenariusz, który jest przeznaczony do procesów kilka flatfiles CSV i czyni to poprzez szeroki zastosowanie gnu join 's' - o opcja auto. Muszę zmodyfikować ten skrypt, aby mógł działać w środowiskach, w których dostępne polecenie join nie obsługuje opcji -o auto (jak w przypadku BSD join, a także w starszych wersjach GNU join).

Typowym zastosowaniem tej opcji w skrypcie jest coś takiego:

_reccut() { 
    cols="1,$1" 
    shift 
    in=$1 
    shift 
    if (($# > 0)); then 
     join -t, -a 1 -a 2 -e 'MISSING' -o auto \ 
      <(cut -d, -f $cols $in | sort -t, -k1) \ 
      <(_reccut "[email protected]") 
    else 
     cut -d, -f $cols $in | sort -t, -k1 
    fi 
} 

pokażę ten przykład, aby pokazać, że trudno byłoby zastąpić -o auto z wyraźnego formatu, ponieważ odpowiednie pola, aby umieścić w tym format nie jest znany przed uruchomieniem.

Powyższa funkcja w zasadzie wyodrębnia kolumny z plików i łączy uzyskane tabele wzdłuż ich pierwszej kolumny.Aby zobaczyć, jak _reccut w akcji, wyobraźmy sobie, że oprócz plików wymienionych powyżej, mieliśmy również plik

de.csv

2,Kaninchen,Grau,Zug 
1,Hund,Rot,Auto 

Następnie, na przykład, aby wyświetlić side-by-side kolumnie 3 en.csv, kolumny 2 i 4 sp.csv i kolumna 3 de.csv można by uruchomić:

% _reccut 3 en.csv 2,4 sp.csv 3 de.csv | cut -d, 2- 
red,MISSING,MISSING,Rot 
MISSING,conejo,tren,Grau 
white,gato,bote,MISSING 
+1

że musiał zrobić dokładnie to, co mówisz o 1-off projektu z sun4, myślę, że "utknąłeś z kodowaniem własnym lub dostarczając nowe GNU join jako część twojej instalacji. Przepraszam, ale powodzenia. – shellter

+1

Sądzę, że powinienem dodać, po wielu kłopotach, skończyłem robienie tablic asoc w awk, z dużo mniejszym kłopotem. Powodzenia. – shellter

Odpowiedz

1

Oto rozwiązanie, które może lub nie może pracować dla danych. Podejrzewa problem przez wyrównanie rekordów w pliku csv według numeru linii, to jest rekord 2 kończy się na linii 2, rekord 3123 na linii numer 3123 i tak dalej. Brakujące zapisy/linie są dopełniane MISSING pól, więc pliki wejściowe będą zniekształcone, aby wyglądać tak:

en.csv:

1,dog,red,car 
2,MISSING,MISSING,MISSING 
3,cat,white,boat 

de.csv:

1,Hund,Rot,Auto 
2,Kaninchen,Grau,Zug 
3,MISSING,MISSING,MISSING 

sp.csv:

1,MISSING,MISSING,MISSING 
2,conejo,gris,tren 
3,gato,blanco,bote 

F tam można łatwo wyciąć interesujące kolumny i wydrukować je obok siebie, używając paste.

Aby to osiągnąć, możemy posortować pliki wejściowe pierwszy a następnie zastosować jakąś głupią awk Magic:

  • Jeśli ich przewidywanej liczby linii pojawi się zapis, wydrukować
  • W przeciwnym razie, druk aż linie zawierające liczbę oczekiwanych (jest to oparte na liczbie pól w pierwszym wierszu w pliku, tak samo jak w przypadku join -o auto)
  • Nie wszystkie pliki wejściowe będą przetwarzane tyle samo rekordów, więc przed tym wszystkim szukane jest maksimum. Następnie, więcej linii z polami MISSING jest drukowanych do momentu uderzenia maksimum.

Kod

reccut.sh:

#!/bin/bash 

get_max_recnum() 
{ 
    awk -F, '{ if ($1 > max) { max = $1 } } END { print max }' "[email protected]" 
} 

align_by_recnum() 
{ 
    sort -t, -k1 "$1" \ 
     | awk -F, -v MAXREC="$2" ' 
      NR==1 { for(x = 1; x < NF; x++) missing = missing ",MISSING" } 
      { 
       i = NR 
       if (NR < $1) 
       { 
        while (i < $1) 
        { 
         print i++ missing 
        } 
        NR+=i 
       } 
      }1 
      END { for(i++; i <= MAXREC; i++) { print i missing } } 
      ' 
} 

_reccut() 
{ 
    local infiles=() 
    local args=([email protected]) 
    for arg; do 
     infiles+=("$2") 
     shift 2 
    done 
    MAXREC="$(get_max_recnum "${infiles[@]}")" __reccut "${args[@]}" 
} 

__reccut() 
{ 
    local cols="$1" 
    local infile="$2" 
    shift 2 

    if (($# > 0)); then 
     paste -d, \ 
      <(align_by_recnum "${infile}" "${MAXREC}" | cut -d, -f ${cols}) \ 
      <(__reccut "[email protected]") 
    else 
     align_by_recnum "${infile}" "${MAXREC}" | cut -d, -f ${cols} 
    fi 
} 

_reccut "[email protected]" 

Run

$ ./reccut.sh 3 en.csv 2,4 sp.csv 3 de.csv 
red,MISSING,MISSING,Rot 
MISSING,conejo,tren,Grau 
white,gato,bote,MISSING 
+0

Byłoby miło, aby uzyskać pewne opinie na ten temat, czy to działa dla Ciebie? –

Powiązane problemy