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.?
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.
$ 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
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).
$ 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
Tout disponible à - http://www.catonmat.net/blog/set-operations-in-unix-shell-sImplified/
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.
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', ...
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.
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).
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 e
xact) 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).
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.
[[ ${(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}} ]]
n=$#array
if ((${#array1:*array2} == ${#array2})); then
echo '$array2 is included in $array1'
fi
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)
complement=("${(@)array1:|array2}")
pour les éléments de $array1
qui ne sont pas dans $array2
.
min=${${(o)array}[1]} max=${${(o)array}[-1]}
min=${${(no)array}[1]} max=${${(no)array}[-1]}
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
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.
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.