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


81

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

回答:


110

要素がNULと改行以外の文字列であると仮定すると(ただし、改行はファイル名に有効であることに注意してください)、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/で入手可能


1
Pythonバージョンは、はるかにシンプルで直感的だと思います。;-)
キース

これが最も完全な答えだと思います。残念ながら、どのコマンドを実行するか、またはどの引数(comm -12、-23、-13)を使用する場合も、それぞれの場合に「交差」または「差分」として必ずしも直感的ではありません。私は常にこれらのものを使用しているので、それらの周りにラッパーを作成するかもしれません。
ニルトン

[pol @ localhost inst] $ grep -xcおよびINSTALL-BINARY 0 [pol @ localhost inst] $を実行しましたが、その意味がわかりません。「and」という単語は、ファイル内で何度も使用する必要があります。何が間違っていますか?
ヴェレース

1
交差の設定:sort set1 set2 | uniq -dマルチセットでは機能しません。の使用を検討してくださいsort <(sort -u set1) <(sort -u set2) | uniq -d
ネオ

11

並べ替え。あなたは自分自身をソートするに対処する必要がありますが、comm集合体として各行を処理し、それを行うために使用することができます: -12交差点のため、-13差を。(そして-23、あなたに反転した差を与えます、つまりset2 - set1set1 - set2。の代わりに。)Unionはsort -uこのセットアップにあります。


1
実際、commはほとんどのことを行うようです。引数は非常に直感的ではありませんが。ありがとう!
ニルトン

7

特定のツールについては知りませんが、Pythonとそのセットクラスと演算子を使用して、それを行うための小さなスクリプトを作成できます。

例:

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

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

はい、いい答えです。Pythonが利用可能な場合にawkを使用する理由
ゲットリ

忘れてしまった:Python> import os
ジェームズバワリー

7

小さなコンソールツール「setop」は、16.10以降、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は、trueの場合にのみ返さ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を参照してください。


3

ファイルが一連の行として表示され、ファイルがソートされている場合、がありcommます。

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

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

2

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

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

1

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

現在、2つのファイルの結合、交差、差、対称差をサポートしています。入力ファイルの各行は、セットの要素として扱われます。

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

フィードバックを歓迎します。


0

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

オペレーション?

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

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


1
ファイルの内容をセットの要素(たとえば、1行に1つの要素)として扱い、ファイル自体をセットとして扱うことを意味しました。
ニルトン

0

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

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

Makefileに記述するのと同様の定義を記述することにより、集合演算を実行できます。

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

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

とにかく、私はそれがかなりクールだと思うとあなたは完全にそれをチェックアウトする必要があります。


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

zshアレイ(zshアレイも0、バイトの任意の配列を含むことができます)。

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

メンバーシップを設定する

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

I配列添え字フラグを使用して、配列内の最後のオカレンスのインデックスを取得します$element(見つからない場合は0)。削除するeexactの場合)$elementパターンとして取得します)

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

${array:#pattern}パターンに一致する先頭部分を単に削除するのではなく、パターンに一致する要素${var#pattern}削除する kshのバリエーションです。(M)(のために一致する)の意味を反転し、マッチした要素(使用が、すべて削除され$~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]}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.