Czy ktoś zna jakieś narzędzie linuksowe zaprojektowane specjalnie do traktowania plików jako zestawów i wykonywania na nich operacji na zestawach? Jak różnica, skrzyżowanie itp.?
81
Czy ktoś zna jakieś narzędzie linuksowe zaprojektowane specjalnie do traktowania plików jako zestawów i wykonywania na nich operacji na zestawach? Jak różnica, skrzyżowanie itp.?
Zakładając, że elementy to ciągi znaków inne niż NUL i nowa linia (uważaj jednak, że nowa nazwa jest poprawna w nazwach plików), możesz reprezentować zestaw jako plik tekstowy z jednym elementem w linii i użyć niektórych standardowych narzędzi uniksowych.
$ grep -Fxc 'element' set # outputs 1 if element is in set
# outputs >1 if set is a multi-set
# outputs 0 if element is not in set
$ grep -Fxq 'element' set # returns 0 (true) if element is in set
# returns 1 (false) if element is not in set
$ awk '$0 == "element" { s=1; exit }; END { exit !s }' set
# returns 0 if element is in set, 1 otherwise.
$ awk -v e='element' '$0 == e { s=1; exit } END { exit !s }'
$ comm -12 <(sort set1) <(sort set2) # outputs intersect of set1 and set2
$ grep -xF -f set1 set2
$ sort set1 set2 | uniq -d
$ join -t <(sort A) <(sort B)
$ awk '!done { a[$0]; next }; $0 in a' set1 done=1 set2
$ cmp -s <(sort set1) <(sort set2) # returns 0 if set1 is equal to set2
# returns 1 if set1 != set2
$ cmp -s <(sort -u set1) <(sort -u set2)
# collapses multi-sets into sets and does the same as previous
$ awk '{ if (!($0 in a)) c++; a[$0] }; END{ exit !(c==NR/2) }' set1 set2
# returns 0 if set1 == set2
# returns 1 if set1 != set2
$ awk '{ a[$0] }; END{ exit !(length(a)==NR/2) }' set1 set2
# same as previous, requires >= gnu awk 3.1.5
$ wc -l < set # outputs number of elements in set
$ awk 'END { print NR }' set
$ sed '$=' set
$ comm -23 <(sort -u subset) <(sort -u set) | grep -q '^'
# returns true iff subset is not a subset of set (has elements not in set)
$ awk '!done { a[$0]; next }; { if !($0 in a) exit 1 }' set done=1 subset
# returns 0 if subset is a subset of set
# returns 1 if subset is not a subset of set
$ cat set1 set2 # outputs union of set1 and set2
# assumes they are disjoint
$ awk 1 set1 set2 # ditto
$ cat set1 set2 ... setn # union over n sets
$ sort -u set1 set2 # same, but doesn't assume they are disjoint
$ sort set1 set2 | uniq
$ awk '!a[$0]++' set1 set2 # ditto without sorting
$ comm -23 <(sort set1) <(sort set2)
# outputs elements in set1 that are not in set2
$ grep -vxF -f set2 set1 # ditto
$ sort set2 set2 set1 | uniq -u # ditto
$ awk '!done { a[$0]; next }; !($0 in a)' set2 done=1 set1
$ comm -3 <(sort set1) <(sort set2) | tr -d '\t' # assumes not tab in sets
# outputs elements that are in set1 or in set2 but not both
$ sort set1 set2 | uniq -u
$ cat <(grep -vxF -f set1 set2) <(grep -vxF -f set2 set1)
$ grep -vxF -f set1 set2; grep -vxF -f set2 set1
$ awk '!done { a[$0]; next }; $0 in a { delete a[$0]; next }; 1;
END { for (b in a) print b }' set1 done=1 set2
Wszystkie możliwe podzbiory zestawu wyświetlanej przestrzeni oddzielone, po jednym w wierszu:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
(zakłada, że elementy nie zawierają SPC, TAB (przy założeniu wartości domyślnej $IFS
), odwrotnego ukośnika, symboli wieloznacznych).
$ while IFS= read -r a; do while IFS= read -r b; do echo "$a, $b"; done < set1; done < set2
$ awk '!done { a[$0]; next }; { for (i in a) print i, $0 }' set1 done=1 set2
$ comm -12 <(sort set1) <(sort set2) # does not output anything if disjoint
$ awk '++seen[$0] == 2 { exit 1 }' set1 set2 # returns 0 if disjoint
# returns 1 if not
$ wc -l < set # outputs 0 if the set is empty
# outputs >0 if the set is not empty
$ grep -q '^' set # returns true (0 exit status) unless set is empty
$ awk '{ exit 1 }' set # returns true (0 exit status) if set is empty
$ sort set | head -n 1 # outputs the minimum (lexically) element in the set
$ awk 'NR == 1 { min = $0 }; $0 < min { min = $0 }; END { print min }'
# ditto, but does numeric comparison when elements are numerical
$ sort test | tail -n 1 # outputs the maximum element in the set
$ sort -r test | head -n 1
$ awk '$0 > max { max = $0 }; END { print max }'
# ditto, but does numeric comparison when elements are numerical
Wszystkie dostępne na stronie http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/
sort set1 set2 | uniq -d
nie działa w przypadku wielu zestawów. Rozważ użyciesort <(sort -u set1) <(sort -u set2) | uniq -d
.Raczej. Musisz poradzić sobie z sortowaniem, ale
comm
możesz tego użyć, traktując każdą linię jako zestaw elementów:-12
na skrzyżowaniu,-13
dla różnicy. (I-23
daje ci odwróconą różnicę, to znaczyset2 - set1
zamiastset1 - set2
.) Union jestsort -u
w tej konfiguracji.źródło
Nie znam konkretnego narzędzia, ale możesz użyć Pythona, jego zestawu klas i operatorów, aby napisać mały skrypt, aby to zrobić.
Na przykład:
źródło
Python> import os
Małe narzędzie konsolowe „setop” jest teraz dostępne w Debian Stretch i Ubuntu od 16.10. Możesz to uzyskać za pośrednictwem
sudo apt install setop
Oto kilka przykładów. Zestawy do obsługi są podane jako różne pliki wejściowe:
setop input # is equal to "sort input --unique" setop file1 file2 --union # option --union is default and can be omitted setop file1 file2 file3 --intersection # more than two inputs are allowed setop file1 - --symmetric-difference # ndash stands for standard input setop file1 -d file2 # all elements contained in 1 but not 2
Zapytania boolowskie zwracane są tylko
EXIT_SUCCESS
w przypadku wartości true, aEXIT_FAILURE
także w innym przypadku. W ten sposób setop może być używany w powłoce.setop inputfile --contains "value" # is element value contained in input? setop A.txt B.txt --equal C.txt # union of A and B equal to C? setop bigfile --subset smallfile # analogous --superset setop -i file1 file2 --is-empty # intersection of 1 and 2 empty (disjoint)?
Możliwe jest również precyzyjne opisanie sposobu analizowania strumieni wejściowych, w rzeczywistości za pomocą wyrażeń regularnych:
setop input.txt --input-separator "[[:space:]-]"
oznacza, że spacja (tj.\v
\t
\n
\r
\f
lub spacja) lub znak minus jest interpretowany jako separator między elementami (domyślnie jest to nowa linia, tzn. każda linia pliku wejściowego to jeden element)setop input.txt --input-element "[A-Za-z]+"
oznacza, że elementy to tylko słowa składające się ze znaków łacińskich, wszystkie pozostałe znaki są uważane za separatory między elementamiPonadto możesz
--count
wszystkie elementy zestawu wyjściowego,--trim
wszystkie elementy wejściowe (tj. usuwają wszystkie niechciane poprzedzające i następujące po sobie znaki, takie jak spacja, przecinek itp.),--include-empty
,--ignore-case
,--output-separator
między elementami strumienia wyjściowego (domyślnie jest\n
),Aby uzyskać więcej informacji, zobacz
man setop
lub github.com/phisigma/setop .źródło
Jeśli widzisz plik jako zestaw linii, a pliki są posortowane, oznacza to, że istnieje
comm
.Jeśli widzisz plik jako (wielokrotny) zestaw linii, a linie nie są posortowane,
grep
może robić różnicę i przecięcie (osiąga ustawioną różnicę i przecięcie, ale nie uwzględnia liczenia dla wielu zestawów). Unia jest sprawiedliwacat
.źródło
Stworzyłem narzędzie Python, które może tworzyć liniowe połączenie, przecięcie, różnicę i iloczyn wielu plików. Nazywa się SetOp, można go znaleźć na PyPI ( tutaj ). Składnia wygląda następująco:
źródło
Napisałem małe narzędzie do tego, które było mi bardzo przydatne w różnych miejscach. Interfejs użytkownika nie jest dopracowany i nie jestem pewien co do wydajności bardzo dużych plików (ponieważ wczytuje całą listę do pamięci), ale „działa dla mnie”. Program znajduje się na https://github.com/nibrahim/lines . Jest w Pythonie. Możesz to uzyskać za pomocą
pip install lines
.Obecnie obsługuje łączenie, przecięcie, różnicę i różnicę symetryczną dwóch plików. Każdy wiersz pliku wejściowego jest traktowany jako element zestawu.
Ma również dwie dodatkowe operacje. Jednym z wyciskania pustych linii w pliku, a drugim (co było dla mnie bardzo przydatne) jest przeglądanie pliku i dzielenie go na zestawy podobnych ciągów. Potrzebowałem tego, aby wyszukać pliki na liście, które nie pasują do ogólnego wzorca.
Chciałbym poznać opinie.
źródło
System plików traktuje nazwy plików (całe nazwy plików, w tym ścieżki) jako unikalne.
Operacje
Możesz skopiować pliki z / ib / do pustego katalogu c /, aby uzyskać nowy zestaw unii.
Dzięki testom plików, takim jak
-e name
i pętle lub find, możesz sprawdzić pliki istniejące w dwóch lub więcej katalogach, aby uzyskać skrzyżowanie lub różnicę.źródło
Najlepsza odpowiedź tutaj: Setdown (dedykowane narzędzie)
Napisałem program o nazwie setdown, który wykonuje operacje Set z cli.
Może wykonywać operacje ustawiania, pisząc definicję podobną do tego, co napisałeś w Makefile:
Jest całkiem fajny i powinieneś to sprawdzić. Ja osobiście nie polecam używania komend ad-hoc, które nie zostały zbudowane dla zadania do wykonywania ustawionych operacji. Nie zadziała to dobrze, gdy naprawdę musisz wykonać wiele operacji ustawiania lub jeśli masz jakieś operacje ustawiania, które są od siebie zależne . Poza tym setdown pozwala pisać operacje na zestawach, które zależą od innych operacji na zestawach!
W każdym razie uważam, że to całkiem fajne i powinieneś to całkowicie sprawdzić.
źródło
Przykładowy wzór dla wielu plików (w tym przypadku przecięcie):
Rozwija się do:
Pliki testowe:
Wynik:
źródło
Z
zsh
tablicami (zsh
tablice mogą zawierać dowolną sekwencję bajtów, nawet 0).(pamiętaj też, że możesz zrobić,
typeset -U array
aby zagwarantować, że jego elementy są unikalne).ustawić członkostwo
(za pomocą
I
flagi indeksu tablicy, aby uzyskać indeks ostatniego wystąpienia$element
w tablicy (lub 0, jeśli nie znaleziono). Usuńe
(dlae
xact),$element
aby zostać wziętym jako wzorzec)${array:#pattern}
jest odmianą ksh,${var#pattern}
która usuwa elementy pasujące do wzorca, a nie tylko usuwa wiodącą część pasującą do wzorca. Opcja(M)
(dla dopasowanego ) odwraca znaczenie i usuwa wszystkie elementy oprócz dopasowanych (użyj$~element
, aby wziąć to jako wzorzec).ustaw przecięcie
${set1:*set2}
robi przecięcie tablicy, ale"${(@)...}"
składnia jest potrzebna do zachowania pustych elementów.ustawić równość
Sprawdza, czy tablice są identyczne (i w tej samej kolejności).
q
Flag ekspansja parametr cytuje elementów (w celu uniknięcia problemów z rzeczy, takich jaka=(1 "2 3")
vsb=("1 2" 3)
) i(j: :)
łączy je z przestrzeni przed wykonaniem porównania ciągów.Aby sprawdzić, czy mają te same elementy, niezależnie od kolejności, użyj
o
flagi, aby je zamówić. Zobacz takżeu
flagę (unikalną), aby usunąć duplikaty.ustawić liczność
test podzestawu
unia
(patrz
typeset -U
wyżej lubu
flaga rozwinięcia parametru, aby uwzględnić przypadki duplikatów). Ponownie, jeśli pusty ciąg nie jest jedną z możliwych wartości, możesz uprościć:komplement
dla elementów
$array1
, których nie ma w$array2
.minimum / maksimum (porównanie leksykalne)
minimum / maksimum (porównanie liczb całkowitych dziesiętnych)
źródło