web-dev-qa-db-fra.com

Outils Linux pour traiter des fichiers comme des ensembles et effectuer des opérations définies sur eux

Quelqu'un est-il connu de tout outil Linux spécialement conçu pour traiter des fichiers comme des ensembles et effectuer des opérations définies sur elles? Comme la différence, l'intersection, etc.?

86
nilton

En supposant que des éléments soient des chaînes de caractères autres que Nul et Newline (méfiez-vous que Newline est valide dans les noms de fichiers), vous pouvez représenter un ensemble sous forme de fichier texte avec un élément par ligne et utilisez certaines des utilitaires UNIX standard.

Mettre l'abonnement

$ 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 }'

Définir l'intersection

$ 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

Définir l'égalité

$ 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

Définir la cardinalité

$ wc -l < set     # outputs number of elements in set

$ awk 'END { print NR }' set

$ sed '$=' set

Test de sous-ensemble

$ 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

Fixer

$ 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

Mettre le complément

$ 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

Définir la différence symétrique

$ 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

Ensemble de puissance

Tous les sous-ensembles possibles d'un espace affiché séparé, un par ligne:

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

(suppose que les éléments ne contiennent pas SPC, onglet (en supposant la valeur par défaut de $IFS), casserole, caractères génériques).

Définir le produit cartésien

$ 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

Test de jeu disjoint

$ 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

Test de jeu vide

$ 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

Le minimum

$ 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

Maximum

$ 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

Tout disponible à - http://www.catonmat.net/blog/set-operations-in-unix-shell-sImplified/

114
llhuii

Sorte de. Vous devez traiter de vous trier vous-même, mais comm peut être utilisé pour le faire, traiter chaque ligne comme membre de l'ensemble: -12 pour intersection, -13 pour la différence. (Et -23 vous donne une différence renversée, c'est-à-dire set2 - set1 à la place de set1 - set2.) Union est sort -u Dans cette configuration.

12
geekosaur

Je ne connais pas d'un outil spécifique, mais vous pouvez utiliser Python et sa classe de jeu et ses opérateurs, pour écrire un petit script pour le faire.

Pour exampe:

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

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

Si vous voyez un fichier en tant que jeu de lignes et que les fichiers sont triés, il y a comm .

Si vous voyez un fichier sous forme de lignes (multi) lignes, et que les lignes ne sont pas triées, grep peut faire la différence et l'intersection (il permet de définir la différence et l'intersection, mais ne respecte pas le nombre de comptes pour les multisets) . Union est juste cat.

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

J'ai écrit un petit outil pour faire cela qui m'a été très utile à divers endroits. L'interface utilisateur est non polie et je ne suis pas sûr des caractéristiques de performance des fichiers très volumineux (puisqu'elle lit toute la liste en mémoire) mais "ça marche pour moi". Le programme est à https://github.com/nibrahim/lines . C'est en python. Vous pouvez l'obtenir en utilisant pip install lines.

Il prend actuellement en charge l'Union, l'intersection, la différence et la différence symétrique de deux fichiers. Chaque ligne du fichier d'entrée est traitée comme un élément d'un ensemble.

Il a également deux opérations supplémentaires. L'une des lignes vierges Squeeze dans un fichier et la seconde (qui m'a été très utile) est de regarder dans le fichier et de la diviser en jeux de chaînes similaires. J'avais besoin de cela pour rechercher des fichiers dans une liste qui ne correspondait pas au modèle général.

J'accueillerais les commentaires.

1
Noufal Ibrahim

Avec zsh tableaux (zsh Les tableaux peuvent contenir toute séquence arbitraire d'octets, même 0).

(Notez également que vous pouvez faire typeset -U array pour garantir que ses éléments sont uniques).

mettre l'abonnement

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

(Utilisation de l'indicateur d'indice I array, pour obtenir l'index de la dernière occurrence de $element dans le tableau (ou 0 non trouvé). Supprimer e (pour exact) pour $element à prendre comme modèle)

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

${array:#pattern} Étant une variation sur ${var#pattern} Que supprime Les éléments qui correspondent au motif par opposition à simplement retirer la partie principale qui correspond au motif. Le (M) (Pour correspondance) annule la signification et supprime tous les éléments correspondants (utilisez $~element Pour qu'il soit pris comme motif).

définir l'intersection

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

${set1:*set2} Est-ce que l'intersection de la matrice, mais la syntaxe "${(@)...}" est nécessaire pour conserver des éléments vides.

définir l'égalité

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

Teste si les tableaux sont identiques (et dans le même ordre). Le drapeau de l'expansion q par paramètre cite les éléments (pour éviter les problèmes de choses telles que a=(1 "2 3") vs b=("1 2" 3)), et (j: :) Les rejoint avant de faire une chaîne avant de faire une corde Comparaison.

Pour vérifier qu'ils ont les mêmes éléments, indépendamment de la commande, utilisez le drapeau o pour les commander. Voir aussi le drapeau u (unique) pour supprimer des duplicats.

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

définir la cardinalité

n=$#array

test de sous-ensemble

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

syndicat

union=("$array1[@]" "$array2[@]")

(Voir typeset -U ci-dessus ou le drapeau d'expansion du paramètre _ u Drapeau d'expansion des paramètres pour prendre des doublons). Encore une fois si la chaîne vide n'est pas l'une des valeurs possibles, vous pouvez simplifier:

union=($array1 $array2)

complément

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

pour les éléments de $array1 qui ne sont pas dans $array2.

minimum/maximum (comparaison lexicale)

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

minimum/maximum (comparaison entière décimale)

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

Exemple de modèle pour plusieurs fichiers (intersection dans ce cas):

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

Développe à:

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

Fichiers de test:

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

Sortir:

0
6
12
18
0
bsb

Meilleure réponse ici: SETDOWN (un outil dédié)

J'ai écrit un programme appelé établissement qui effectue des opérations définies de la CLI.

Il peut effectuer des opérations définies en écrivant une définition similaire à ce que vous écririez dans un makefile:

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

C'est assez cool et vous devriez vérifier. Personnellement, je ne recommande pas d'utiliser des commandes ad-hoc qui n'ont pas été construites pour effectuer les opérations définies.Il ne fonctionnera pas bien lorsque vous devez vraiment faire de nombreuses opérations définies ou si vous avez des opérations définies qui dépendent l'une de l'autre. . Non seulement cela, mais la configuration vous permet d'écrire des opérations définies qui dépendent d'autres opérations définies!

En tout cas, je pense que c'est assez cool et vous devriez totalement vérifier.

0
Robert Massaioli

Le système de fichiers traite des noms de fichiers (noms de fichiers entiers, y compris les chemins) comme unique.

Opérations?

Vous pouvez copier les fichiers dans A/et B/vers le répertoire vide C /, pour obtenir un nouveau jeu union.

Avec des tests de fichiers comme -e name et boucles ou trouvez, vous pouvez vérifier les fichiers existants dans deux répertoires ou plus, pour obtenir l'intersection ou la différence.

0
user unknown