Câu trả lời:
Giả sử các phần tử là các chuỗi ký tự không phải là NUL và dòng mới (hãy coi chừng dòng mới là hợp lệ trong tên tệp), bạn có thể biểu diễn một tập hợp dưới dạng tệp văn bản với một thành phần trên mỗi dòng và sử dụng một số tiện ích Unix tiêu chuẩn.
$ 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
Tất cả các tập hợp con có thể có của một tập hợp không gian hiển thị được phân tách, một không gian trên mỗi dòng:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
(giả sử các phần tử không chứa SPC, TAB (giả sử giá trị mặc định là $IFS
), dấu gạch chéo ngược, ký tự đại diện).
$ 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
Tất cả có sẵn tại http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/
sort set1 set2 | uniq -d
không hoạt động cho nhiều bộ. Cân nhắc sử dụng sort <(sort -u set1) <(sort -u set2) | uniq -d
.
Sắp xếp Bạn cần phải đối phó với việc tự sắp xếp, nhưng comm
có thể được sử dụng để làm điều đó, coi mỗi dòng là một thành viên đã đặt: -12
cho giao lộ, -13
cho sự khác biệt. (Và -23
cung cấp cho bạn sự khác biệt lật, nghĩa là, set2 - set1
thay vì set1 - set2
.) Union nằm sort -u
trong thiết lập này.
Tôi không biết về một công cụ cụ thể nhưng bạn có thể sử dụng Python, và lớp toán tử và toán tử của nó, để viết một tập lệnh nhỏ để làm điều đó.
Đối với exampe:
Python> s1 = set(os.listdir("/bin"))
Python> s2 = set(os.listdir("/usr/bin"))
Python> s1 & s2
set(['awk',
'basename',
'chroot', ...
Python> import os
Công cụ bàn điều khiển nhỏ bé cài đặt trực tuyến có sẵn trong Debian Stretch và trong Ubuntu kể từ 16.10. Bạn có thể lấy nó qua
sudo apt install setop
Dưới đây là một số ví dụ. Các bộ được vận hành trên được cung cấp dưới dạng các tệp đầu vào khác nhau:
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
Các truy vấn Boolean chỉ trả về EXIT_SUCCESS
trong trường hợp đúng và EXIT_FAILURE
cũng như một thông báo khác. Bằng cách này, setop có thể được sử dụng trong 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)?
Cũng có thể mô tả chính xác cách các luồng đầu vào sẽ được phân tích cú pháp, thực sự bằng các biểu thức thông thường:
setop input.txt --input-separator "[[:space:]-]"
có nghĩa là khoảng trắng (nghĩa là khoảng trắng \v
\t
\n
\r
\f
) hoặc dấu trừ được hiểu là dấu phân cách giữa các phần tử (mặc định là dòng mới, tức là mỗi dòng của tệp đầu vào là một phần tử)setop input.txt --input-element "[A-Za-z]+"
có nghĩa là các thành phần chỉ là các từ bao gồm các ký tự Latin, tất cả các ký tự khác được coi là dấu phân cách giữa các thành phầnHơn nữa, bạn có thể
--count
tất cả các yếu tố của bộ đầu ra,--trim
tất cả các yếu tố đầu vào (nghĩa là xóa tất cả các ký tự không mong muốn và thành công trước đó như dấu cách, dấu phẩy, v.v.),--include-empty
,--ignore-case
,--output-separator
giữa các thành phần của luồng đầu ra (mặc định là \n
),Xem man setop
hoặc github.com/p4igma/setop để biết thêm thông tin.
Nếu bạn thấy một tệp là một tập hợp các dòng và các tệp được sắp xếp, thì có comm
.
Nếu bạn thấy một tệp dưới dạng một tập hợp (nhiều) dòng và các dòng không được sắp xếp, grep
có thể tạo ra sự khác biệt và giao nhau (nó đạt được sự khác biệt và giao nhau, nhưng không tôn trọng số lượng cho nhiều trang). Liên minh chỉ là cat
.
grep -xF -f small large >intersection
grep -vxF -f small large >difference
cat small large >union
Tôi đã tạo một tiện ích Python có thể thực hiện liên kết dòng, giao nhau, khác biệt và sản phẩm của nhiều tệp. Nó được gọi là SetOp, bạn có thể tìm thấy nó trên PyPI ( tại đây ). Cú pháp trông như thế này:
$ setop -i file1 file2 file3 # intersection
$ setop -d file1 file2 file3 # difference
Tôi đã viết một công cụ nhỏ để làm việc này khá hữu ích với tôi ở nhiều nơi. Giao diện người dùng chưa được chỉnh sửa và tôi không chắc về các đặc tính hiệu suất cho các tệp rất lớn (vì nó đọc toàn bộ danh sách vào bộ nhớ) nhưng "nó hoạt động với tôi". Chương trình có tại https://github.com/nibrahim/lines . Nó ở trong Python. Bạn có thể lấy nó bằng cách sử dụng pip install lines
.
Nó hiện hỗ trợ hợp nhất, giao nhau, khác biệt và khác biệt đối xứng của hai tệp. Mỗi dòng của tệp đầu vào được coi là một thành phần của tập hợp.
Nó cũng có hai hoạt động thêm. Một trong những vắt kiệt các dòng trống trong một tệp và thứ hai (rất hữu ích với tôi) là xem qua tệp và chia nó thành các chuỗi tương tự. Tôi cần điều này để tìm các tệp trong danh sách không khớp với mẫu chung.
Tôi hoan nghênh phản hồi.
Hệ thống tập tin coi tên tệp (toàn bộ tên tệp, bao gồm cả đường dẫn) là duy nhất.
Hoạt động?
Bạn có thể sao chép các tệp trong a / và b / vào thư mục trống c /, để có được một tập hợp mới.
Với các bài kiểm tra tệp như -e name
vòng lặp và tìm hoặc tìm, bạn có thể kiểm tra các tệp hiện có trong hai hoặc nhiều thư mục, để có giao điểm hoặc sự khác biệt.
Câu trả lời hay nhất ở đây: Setdown (một công cụ chuyên dụng)
Tôi đã viết một chương trình gọi là setdown thực hiện các thao tác Set từ cli.
Nó có thể thực hiện các thao tác thiết lập bằng cách viết một định nghĩa tương tự như những gì bạn sẽ viết trong Makefile:
someUnion: "file-1.txt" \/ "file-2.txt"
someIntersection: "file-1.txt" /\ "file-2.txt"
someDifference: someUnion - someIntersection
Nó khá mát mẻ và bạn nên kiểm tra nó. Cá nhân tôi không khuyên bạn nên sử dụng các lệnh ad-hoc không được xây dựng cho công việc để thực hiện các thao tác thiết lập. Nó sẽ không hoạt động tốt khi bạn thực sự cần thực hiện nhiều thao tác thiết lập hoặc nếu bạn có bất kỳ thao tác thiết lập nào phụ thuộc vào nhau . Không chỉ vậy mà setdown cho phép bạn viết các hoạt động thiết lập phụ thuộc vào các hoạt động thiết lập khác!
Ở mức độ nào, tôi nghĩ rằng nó khá tuyệt và bạn hoàn toàn nên kiểm tra nó.
Với zsh
các mảng ( zsh
mảng có thể chứa bất kỳ chuỗi byte tùy ý, thậm chí 0).
(cũng lưu ý rằng bạn có thể làm typeset -U array
để đảm bảo các yếu tố của nó là duy nhất).
if ((${array[(Ie)$element]})); then
echo '$element is in $array'
fi
(sử dụng I
cờ đăng ký mảng, để lấy chỉ mục của lần xuất hiện cuối cùng $element
trong mảng (hoặc 0 nếu không tìm thấy). Xóa e
(đối với e
xact) $element
để được lấy làm mẫu)
if ((n = ${(M)#array:#$element})); then
echo "\$element is found $n times in \$array'
fi
${array:#pattern}
là một biến thể của ksh ${var#pattern}
giúp loại bỏ các yếu tố phù hợp với mẫu trái ngược với chỉ loại bỏ phần đầu phù hợp với mẫu. Các (M)
(cho phù hợp ) đảo ngược ý nghĩa và loại bỏ tất cả ngoại trừ các yếu tố phù hợp (sử dụng $~element
cho nó được thực hiện như là một mô hình).
common=("${(@)set1:*set2}")
${set1:*set2}
thực hiện giao điểm mảng, nhưng "${(@)...}"
cú pháp là cần thiết để bảo toàn các phần tử trống.
[[ ${(j: :)${(q)array1}} = ${(j: :)${(q)array2}} ]]
Kiểm tra xem các mảng có giống nhau không (và theo cùng một thứ tự). Các q
cờ mở rộng tham số trích các yếu tố (để tránh các vấn đề với những thứ như a=(1 "2 3")
vs b=("1 2" 3)
), và (j: :)
gia nhập chúng với không gian trước khi làm một so sánh chuỗi.
Để kiểm tra xem chúng có các phần tử giống nhau không, không phân biệt thứ tự, sử dụng o
cờ để sắp xếp chúng. Xem thêm u
cờ (duy nhất) để loại bỏ trùng lặp.
[[ ${(j: :)${(qo)array1}} = ${(j: :)${(qo)array2}} ]]
n=$#array
if ((${#array1:*array2} == ${#array2})); then
echo '$array2 is included in $array1'
fi
union=("$array1[@]" "$array2[@]")
(xem typeset -U
ở trên hoặc u
cờ mở rộng tham số để lấy trường hợp trùng lặp). Một lần nữa nếu chuỗi trống không phải là một trong những giá trị có thể, bạn có thể đơn giản hóa thành:
union=($array1 $array2)
complement=("${(@)array1:|array2}")
cho các yếu tố $array1
đó không phải là trong $array2
.
min=${${(o)array}[1]} max=${${(o)array}[-1]}
min=${${(no)array}[1]} max=${${(no)array}[-1]}