nil*_*ton 91 command-line utilities text-processing
有谁知道任何专门用于将文件视为集合并对它们执行集合操作的 Linux 工具?像差异,交集等?
llh*_*uii 119
假设元素是除 NUL 和换行符之外的字符串(请注意,换行符在文件名中是有效的),您可以将集合表示为每行一个元素的文本文件,并使用一些标准的 Unix 实用程序。
$ 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 }'
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ wc -l < set # outputs number of elements in set
$ awk 'END { print NR }' set
$ sed '$=' set
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
一组显示空间的所有可能子集分开,每行一个:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
Run Code Online (Sandbox Code Playgroud)
(假设元素不包含 SPC、TAB(假设默认值为$IFS)、反斜杠、通配符)。
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
所有可用在http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/
gee*_*aur 14
有点。您需要自己处理排序,但comm可以用来做到这一点,将每条线视为一个集合成员: -12用于交集,-13用于差异。(并-23为您提供翻转差异,即,set2 - set1而不是set1 - set2。)联合sort -u在此设置中。
Fra*_*ank 10
自 16.10 起,小型控制台工具“setop”现在可用于 Debian Stretch 和 Ubuntu。你可以通过
sudo apt install setop
这里有些例子。要操作的集合作为不同的输入文件给出:
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
布尔查询仅EXIT_SUCCESS在为真时返回,EXIT_FAILURE否则返回消息。这样,就可以在shell 中使用setop。
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)?
也可以精确地描述如何解析输入流,实际上是通过正则表达式:
setop input.txt --input-separator "[[:space:]-]"表示空格(即\v \t \n \r \f或空格)或减号被解释为元素之间的分隔符(默认为新行,即输入文件的每一行都是一个元素)setop input.txt --input-element "[A-Za-z]+" 意味着元素只是由拉丁字符组成的单词,所有其他字符都被认为是元素之间的分隔符此外,您可以
--count 输出集的所有元素,--trim 所有输入元素(即删除所有不需要的前后字符,如空格、逗号等),--include-empty,--ignore-case,--output-separator输出流的元素之间(默认为\n),有关更多信息,请参阅man setop或github.com/phisigma/setop。
我不知道有什么特定的工具,但您可以使用 Python 及其集合类和运算符来编写一个小脚本来执行此操作。
例如:
Python> s1 = set(os.listdir("/bin"))
Python> s2 = set(os.listdir("/usr/bin"))
Python> s1 & s2
set(['awk',
'basename',
'chroot', ...
Run Code Online (Sandbox Code Playgroud)