Apakah ada yang tahu tentang alat linux yang dirancang khusus untuk memperlakukan file sebagai set dan melakukan operasi set pada mereka? Suka perbedaan, persimpangan, dll?
82
Apakah ada yang tahu tentang alat linux yang dirancang khusus untuk memperlakukan file sebagai set dan melakukan operasi set pada mereka? Suka perbedaan, persimpangan, dll?
Dengan asumsi elemen adalah rangkaian karakter selain NUL dan baris baru (berhati-hatilah bahwa baris baru itu valid dalam nama file), Anda dapat mewakili satu set sebagai file teks dengan satu elemen per baris dan menggunakan beberapa utilitas Unix standar.
$ 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
Semua himpunan bagian dari himpunan ditampilkan ditampilkan terpisah, satu per baris:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
(mengasumsikan elemen tidak mengandung SPC, TAB (dengan asumsi nilai default $IFS
), backslash, karakter wildcard).
$ 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
Semua tersedia di http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/
sort set1 set2 | uniq -d
tidak berfungsi untuk multi-set. Pertimbangkan untuk menggunakansort <(sort -u set1) <(sort -u set2) | uniq -d
.Semacam. Anda perlu berurusan dengan penyortiran diri sendiri, tetapi
comm
dapat digunakan untuk melakukan itu, memperlakukan setiap baris sebagai anggota yang ditetapkan:-12
untuk persimpangan,-13
untuk perbedaan. (Dan-23
memberi Anda membalik perbedaan, yaitu,set2 - set1
bukannyaset1 - set2
.) Serikatsort -u
dalam pengaturan ini.sumber
Saya tidak tahu alat tertentu tetapi Anda dapat menggunakan Python, dan kelas yang ditetapkan dan operator, untuk menulis skrip kecil untuk melakukan itu.
Sebagai contoh:
sumber
Python> import os
Alat kecil "setop" sekarang tersedia di Debian Stretch dan di Ubuntu sejak 16.10. Anda bisa mendapatkannya via
sudo apt install setop
Berikut ini beberapa contohnya. Set untuk dioperasikan diberikan sebagai file input yang berbeda:
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
Kueri Boolean hanya mengembalikan
EXIT_SUCCESS
jika benar, danEXIT_FAILURE
juga pesan sebaliknya. Dengan cara ini, setop dapat digunakan dalam shell.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)?
Dimungkinkan juga untuk mendeskripsikan sebelumnya bagaimana aliran input harus diuraikan, sebenarnya dengan ekspresi reguler:
setop input.txt --input-separator "[[:space:]-]"
berarti spasi putih (yaitu\v
\t
\n
\r
\f
spasi) atau tanda minus ditafsirkan sebagai pemisah antara elemen (standarnya adalah baris baru, yaitu setiap baris file input adalah satu elemen)setop input.txt --input-element "[A-Za-z]+"
berarti elemen hanya kata-kata yang terdiri dari karakter latin, semua karakter lain dianggap sebagai pemisah antar elemenSelanjutnya, Anda bisa
--count
semua elemen dari set output,--trim
semua elemen input (yaitu, menghapus semua karakter yang sebelumnya dan sebelumnya yang tidak diinginkan seperti spasi, koma dll.),--include-empty
,--ignore-case
,--output-separator
elemen-elemen dari aliran output (standarnya adalah\n
),Lihat
man setop
atau github.com/phisigma/setop untuk informasi lebih lanjut.sumber
Jika Anda melihat file sebagai kumpulan garis, dan file diurutkan, ada
comm
.Jika Anda melihat file sebagai kumpulan (multi) baris, dan baris tidak diurutkan,
grep
dapat melakukan perbedaan dan persimpangan (mencapai perbedaan set dan persimpangan, tetapi tidak menghormati hitungan multiset). Persatuan itu adilcat
.sumber
Saya telah membuat utilitas Python yang dapat melakukan penyatuan garis, persimpangan, perbedaan, dan produk dari banyak file. Ini disebut SetOp, Anda dapat menemukannya di PyPI (di sini ). Sintaksnya terlihat seperti ini:
sumber
Saya menulis alat kecil untuk melakukan ini yang telah sangat berguna bagi saya di berbagai tempat. UI tidak dipoles dan saya tidak yakin tentang karakteristik kinerja untuk file yang sangat besar (karena membaca seluruh daftar ke dalam memori) tetapi "itu bekerja untuk saya". Program ini ada di https://github.com/nibrahim/lines . Ada dalam Python. Anda bisa menggunakannya
pip install lines
.Saat ini mendukung penyatuan, persimpangan, perbedaan dan perbedaan simetris dari dua file. Setiap baris dari file input diperlakukan sebagai elemen dari set.
Ini juga memiliki dua operasi tambahan. Salah satu dari memeras baris kosong dalam file dan yang kedua (yang telah sangat berguna bagi saya) adalah untuk melihat file dan membaginya menjadi set string yang serupa. Saya memerlukan ini untuk mencari file dalam daftar yang tidak cocok dengan pola umum.
Saya akan menyambut umpan balik.
sumber
Filesystem memperlakukan nama file (seluruh nama file, termasuk jalur) sebagai unik.
Operasi?
Anda dapat menyalin file di a / dan b / ke direktori kosong c /, untuk mendapatkan set union yang baru.
Dengan tes file seperti
-e name
dan loop atau temukan, Anda dapat memeriksa file yang ada di dua atau lebih direktori, untuk mendapatkan persimpangan, atau perbedaannya.sumber
Jawaban terbaik di sini: Setdown (alat khusus)
Saya menulis sebuah program bernama setdown yang melakukan operasi Set dari cli.
Itu dapat melakukan operasi yang ditetapkan dengan menulis definisi yang mirip dengan apa yang akan Anda tulis di Makefile:
Cukup keren dan Anda harus memeriksanya. Saya pribadi tidak merekomendasikan menggunakan perintah ad-hoc yang tidak dibangun untuk pekerjaan untuk melakukan operasi yang ditetapkan. Ini tidak akan bekerja dengan baik ketika Anda benar-benar perlu melakukan banyak operasi yang ditetapkan atau jika Anda memiliki operasi yang ditetapkan yang saling bergantung satu sama lain . Bukan hanya itu tetapi penurunan memungkinkan Anda menulis operasi yang tergantung pada operasi yang ditetapkan lainnya!
Bagaimanapun, saya pikir itu sangat keren dan Anda harus benar-benar memeriksanya.
sumber
Pola sampel untuk banyak file (persimpangan dalam kasus ini):
Perluas ke:
File uji:
Keluaran:
sumber
Dengan
zsh
array (zsh
array dapat berisi urutan byte, bahkan 0).(perhatikan juga yang dapat Anda lakukan
typeset -U array
untuk memastikan elemen-elemennya unik).mengatur keanggotaan
(menggunakan
I
flag subscript array, untuk mendapatkan indeks kejadian terakhir$element
dalam array (atau 0 jika tidak ditemukan). Hapuse
(untuke
xact) untuk$element
diambil sebagai pola)${array:#pattern}
menjadi variasi pada ksh${var#pattern}
yang menghilangkan elemen yang cocok dengan pola dan bukan hanya menghapus bagian utama yang cocok dengan pola. The(M)
(untuk cocok ) membalikkan makna dan menghapus semua namun unsur cocok (gunakan$~element
untuk itu harus diambil sebagai pola).mengatur persimpangan
${set1:*set2}
melakukan persimpangan array, tetapi"${(@)...}"
sintaks diperlukan untuk mempertahankan elemen kosong.mengatur kesetaraan
Menguji apakah array identik (dan dalam urutan yang sama). The
q
bendera ekspansi parameter mengutip elemen (untuk menghindari masalah dengan hal-hal sepertia=(1 "2 3")
vsb=("1 2" 3)
), dan(j: :)
bergabung dengan mereka dengan ruang sebelum melakukan perbandingan string.Untuk memeriksa bahwa mereka memiliki elemen yang sama, terlepas dari pesanan, gunakan
o
bendera untuk memesannya. Lihat jugau
bendera (unik) untuk menghapus duplikat.mengatur kardinalitas
tes subset
Persatuan
(lihat di
typeset -U
atas atauu
bendera ekspansi parameter untuk mengambil kasus duplikat). Sekali lagi jika string kosong bukan salah satu dari nilai yang mungkin, Anda dapat menyederhanakan untuk:melengkapi
untuk elemen
$array1
yang tidak ada dalam$array2
.minimum / maksimum (perbandingan leksikal)
minimum / maksimum (perbandingan bilangan desimal)
sumber