web-dev-qa-db-ja.com

ファイルをセットとして扱い、それらに対してセット操作を実行するLinuxツール

ファイルをセットとして扱い、それらに対してセット操作を実行するように特別に設計されたLinuxツールを知っている人はいますか?違いや交差点などは?

86
nilton

要素がNULおよび改行以外の文字列であると仮定すると(ただし、改行はファイル名で有効であることに注意してください)、setをテキストファイルとして表すことができます。 1行に1つの要素があり、いくつかの標準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 }'

交差を設定

$ 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

パワーセット

セットのすべての可能なサブセットは、1行に1つずつ、スペースで区切られて表示されます。

$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
        while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)

(要素に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

素集合テスト

$ 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

すべては http://www.catonmat.net/blog/set-operations-in-unix-Shell-simplified/ で入手できます

114
llhuii

ちょっと。自分でソートする必要がありますが、commを使用して各行をセットメンバーとして処理できます:交差の場合は-12、差の場合は-13。 (そして-23を使用すると、違いが反転します。つまり、set2 - set1ではなくset1 - set2になります。)この設定では、Unionはsort -uです。

12
geekosaur

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_

ブールクエリは、trueの場合は_EXIT_SUCCESS_のみを返し、そうでない場合は_EXIT_FAILURE_とメッセージを返します。このように、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_またはスペース)またはマイナス記号が要素間の区切り文字として解釈されることを意味します(デフォルトは改行です。つまり、入力ファイルのすべての行が1つの要素です)
  • _setop input.txt --input-element "[A-Za-z]+"_は、要素がラテン文字で構成される単語のみであり、他のすべての文字は要素間の区切り文字と見なされることを意味します

さらに、

  • _--count_出力セットのすべての要素、
  • _--trim_すべての入力要素(つまり、スペース、コンマなどの不要な前後の文字をすべて削除します)、
  • 空の要素を_--include-empty_を介して有効であると見なし、
  • _--ignore-case_、
  • 出力ストリームの要素間に_--output-separator_を設定します(デフォルトは_\n_です)、
  • 等々。

詳細については、_man setop_または github.com/phisigma/setop を参照してください。

9
Frank

私は特定のツールを知りませんが、Pythonとそのセットクラスと演算子を使用して、それを行う小さなスクリプトを書くことができます。

たとえば:

Python> s1 = set(os.listdir("/bin"))
Python> s2 = set(os.listdir("/usr/bin"))
Python> s1 & s2

set(['awk',
     'basename',
     'chroot', ...
8
Keith

ファイルが一連の行として表示され、ファイルが並べ替えられている場合、 comm があります。

ファイルが行の(マルチ)セットとして表示され、行がソートされていない場合、grepは差と交差を実行できます(セットの差と交差を実現しますが、マルチセットのカウントは考慮しません)。 。 Unionはcatです。

grep -xF -f small large >intersection
grep -vxF -f small large >difference
cat small large >union

私はPythonユーティリティを作成しました。これは、複数のファイルの行ごとの結合、交差、差、積を実行できます。これはSetOpと呼ばれ、PyPIで見つけることができます( こちら) )。構文は次のようになります:

$ setop -i file1 file2 file3  # intersection
$ setop -d file1 file2 file3  # difference
2
Tigr

これを行うための小さなツールを書いたので、さまざまな場所でとても役に立ちました。 UIは洗練されておらず、非常に大きなファイルのパフォーマンス特性についてはわかりません(リスト全体をメモリに読み込むため)。プログラムは https://github.com/nibrahim/lines にあります。それはPythonです。 pip install linesを使用して取得できます。

現在、2つのファイルのユニオン、インターセクション、差分、対称差分をサポートしています。入力ファイルの各行は、セットの要素として扱われます。

また、2つの追加操作があります。ファイル内の空白行を絞り出す方法の1つと2番目の方法(これは私にとって非常に便利です)は、ファイルを調べて、類似した文字列のセットに分割することです。一般的なパターンに一致しないファイルをリストから探すために、これが必要でした。

フィードバックをお待ちしています。

1
Noufal Ibrahim

zsh配列の場合(zsh配列には、任意のバイトシーケンスを含めることができます。0でも可)。

(その要素が一意であることを保証するために_typeset -U array_を実行できることにも注意してください)。

メンバーシップを設定

_if ((${array[(Ie)$element]})); then
  echo '$element is in $array'
fi
_

I配列添え字フラグを使用して、配列内の_$element_の最後の出現のインデックスを取得します(見つからない場合は0)。eを削除します(exact)__$element_をパターンとして使用)

_if ((n = ${(M)#array:#$element})); then
  echo "\$element is found $n times in \$array'
fi
_

_${array:#pattern}_は、kshの_${var#pattern}_のバリエーションです削除パターンに一致する要素を削除するのではなく、パターンに一致する要素を削除します。 _(M)_(for matched)は、意味を逆にして、一致した要素以外をすべて削除します(パターンとして使用するには、_$~element_を使用します)。

交差点を設定

_common=("${(@)set1:*set2}")
_

_${set1:*set2}_は配列の交差を行いますが、空の要素を保持するには"${(@)...}"構文が必要です。

平等を設定する

_[[ ${(j: :)${(q)array1}} = ${(j: :)${(q)array2}} ]]
_

配列が同一(かつ同じ順序)かどうかをテストします。 qパラメータ展開フラグは要素を引用符で囲み(a=(1 "2 3")b=("1 2" 3)などの問題を回避するため)、_(j: :)_はスペースを使用して要素を結合してから文字列比較。

順序に関係なく、これらの要素が同じであることを確認するには、oフラグを使用して順序付けします。重複を削除するには、uフラグ(一意)も参照してください。

_[[ ${(j: :)${(qo)array1}} = ${(j: :)${(qo)array2}} ]]
_

カーディナリティを設定する

_n=$#array
_

サブセットテスト

_if ((${#array1:*array2} == ${#array2})); then
  echo '$array2 is included in $array1'
fi
_

連合

_union=("$array1[@]" "$array2[@]")
_

(上記の_typeset -U_またはuパラメータ展開フラグを参照して、重複の場合を考慮してください)。ここでも、空の文字列が可能な値の1つでない場合は、次のように簡略化できます。

_union=($array1 $array2)
_

補体

_complement=("${(@)array1:|array2}")
_

_$array1_にない_$array2_の要素の場合。

最小/最大(字句比較)

_min=${${(o)array}[1]} max=${${(o)array}[-1]}
_

最小/最大(10進整数比較)

_min=${${(no)array}[1]} max=${${(no)array}[-1]}
_
0

複数ファイルのサンプルパターン(この場合は交差):

eval `Perl -le 'print "cat ",join(" | grep -xF -f- ", @ARGV)' t*`

展開する:

cat t1 | grep -xF -f- t2 | grep -xF -f- t3

テストファイル:

seq 0 20 | tee t1; seq 0 2 20 | tee t2; seq 0 3 20 | tee t3

出力:

0
6
12
18
0
bsb

ここでのベストアンサー: Setdown(専用ツール)

私は、cliからSet操作を実行するsetdownというプログラムを作成しました。

Makefileに書き込むのと同様の定義を書き込むことで、セット操作を実行できます。

someUnion: "file-1.txt" \/ "file-2.txt"
someIntersection: "file-1.txt" /\ "file-2.txt"
someDifference: someUnion - someIntersection

そのかなりクールで、あなたはそれをチェックする必要があります。個人的には、セット操作を実行するジョブ用に作成されていないアドホックコマンドを使用することはお勧めしません。多くのセット操作を実行する必要がある場合や、相互に依存するセット操作がある場合は、うまく機能しません。 。それだけでなく、setdownを使用すると、他の集合演算に依存する集合演算を記述できます。

とにかくすごくかっこいいので、是非チェックしてみてください。

0

ファイルシステムは、ファイル名(パスを含むファイル名全体)を一意のものとして扱います。

操作?

A /およびb /のファイルを空のディレクトリc /にコピーして、新しいユニオンセットを取得できます。

-e nameのようなファイルテストとループまたは検索を使用すると、2つ以上のディレクトリに存在するファイルをチェックして、共通部分または相違点を取得できます。

0
user unknown