¿Alguien sabe de alguna herramienta de Linux específicamente diseñada para tratar archivos como conjuntos y realizar operaciones de conjunto en ellos? ¿Como diferencia, intersección, etc.?
82
¿Alguien sabe de alguna herramienta de Linux específicamente diseñada para tratar archivos como conjuntos y realizar operaciones de conjunto en ellos? ¿Como diferencia, intersección, etc.?
Suponiendo que los elementos son cadenas de caracteres distintos de NUL y nueva línea (tenga en cuenta que la nueva línea es válida en los nombres de archivo), puede representar un conjunto como un archivo de texto con un elemento por línea y utilizar algunas de las utilidades estándar de 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
Todos los subconjuntos posibles de un conjunto muestran espacios separados, uno por línea:
$ p() { [ "$#" -eq 0 ] && echo || (shift; p "$@") |
while read r; do printf '%s %s\n%s\n' "$1" "$r" "$r"; done; }
$ p $(cat set)
(asume que los elementos no contienen SPC, TAB (asumiendo el valor predeterminado de $IFS
), barra invertida, caracteres comodín).
$ 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
Todo disponible en http://www.catonmat.net/blog/set-operations-in-unix-shell-simplified/
sort set1 set2 | uniq -d
no funciona para conjuntos múltiples. Considera usarsort <(sort -u set1) <(sort -u set2) | uniq -d
.Algo así como. Debe lidiar con la clasificación usted mismo, pero
comm
puede usarse para hacer eso, tratando cada línea como un miembro fijo:-12
por intersección,-13
por diferencia. (Y-23
le da una diferencia invertida, es decir, enset2 - set1
lugar deset1 - set2
). Union estásort -u
en esta configuración.fuente
No conozco una herramienta específica, pero puede usar Python, y su clase de conjunto y operadores, para escribir un pequeño script para hacer eso.
Por ejemplo:
fuente
Python> import os
La pequeña herramienta de consola "setop" ahora está disponible en Debian Stretch y en Ubuntu desde la 16.10. Puedes obtenerlo a través de
sudo apt install setop
Aquí hay unos ejemplos. Los conjuntos a operar se proporcionan como diferentes archivos de entrada:
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
Las consultas booleanas solo se devuelven
EXIT_SUCCESS
en caso de ser verdaderas, yEXIT_FAILURE
también un mensaje en caso contrario De esta manera, setop se puede usar en el shell.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)?
También es posible describir con precisión cómo se analizarán los flujos de entrada, en realidad mediante expresiones regulares:
setop input.txt --input-separator "[[:space:]-]"
significa que un espacio en blanco (es decir,\v
\t
\n
\r
\f
o espacio) o un signo menos se interpreta como un separador entre elementos (el valor predeterminado es una nueva línea, es decir, cada línea del archivo de entrada es un elemento)setop input.txt --input-element "[A-Za-z]+"
significa que los elementos son solo palabras que consisten en caracteres latinos, todos los demás caracteres se consideran separadores entre elementosAdemás, puedes
--count
todos los elementos del conjunto de salida,--trim
todos los elementos de entrada (es decir, borrar todos los caracteres anteriores y posteriores no deseados como espacio, coma, etc.)--include-empty
,--ignore-case
,--output-separator
elementos entre la secuencia de salida (el valor predeterminado es\n
),Visite
man setop
o github.com/phisigma/setop para obtener más información.fuente
Si ve un archivo como un conjunto de líneas, y los archivos están ordenados, hay
comm
.Si ve un archivo como un conjunto (múltiple) de líneas, y las líneas no están ordenadas,
grep
puede hacer la diferencia y la intersección (logra la diferencia y la intersección establecidas, pero no respeta el recuento de varios conjuntos). La unión es justacat
.fuente
Hice una utilidad Python que puede hacer unión, intersección, diferencia y producto de múltiples archivos en línea. Se llama SetOp, puedes encontrarlo en PyPI ( aquí ). La sintaxis se ve así:
fuente
Escribí una pequeña herramienta para hacer esto que me ha sido muy útil en varios lugares. La interfaz de usuario no está pulida y no estoy seguro de las características de rendimiento para archivos muy grandes (ya que lee la lista completa en la memoria) pero "funciona para mí". El programa está en https://github.com/nibrahim/lines . Está en Python. Puedes conseguirlo usando
pip install lines
.Actualmente admite unión, intersección, diferencia y diferencia simétrica de dos archivos. Cada línea del archivo de entrada se trata como un elemento de un conjunto.
También tiene dos operaciones adicionales. Una de las líneas en blanco en un archivo y la segunda (que me ha sido muy útil) es mirar a través del archivo y dividirlo en conjuntos de cadenas similares. Necesitaba esto para buscar archivos en una lista que no coincide con el patrón general.
Agradecería cualquier comentario.
fuente
El sistema de archivos trata los nombres de archivo (nombres de archivo completos, incluidas las rutas) como únicos.
Operaciones?
Puede copiar los archivos en a / yb / en el directorio vacío c /, para obtener un nuevo conjunto de unión.
Con pruebas de archivos como
-e name
y bucles o find, puede verificar los archivos existentes en dos o más directorios, para obtener la intersección o la diferencia.fuente
La mejor respuesta aquí: Setdown (una herramienta dedicada)
Escribí un programa llamado setdown que realiza operaciones Set desde el cli.
Puede realizar operaciones de conjunto escribiendo una definición similar a la que escribiría en un Makefile:
Es genial y deberías echarle un vistazo. Personalmente, no recomiendo usar comandos ad-hoc que no se hayan creado para el trabajo para realizar operaciones de conjuntos. No funcionará bien cuando realmente necesite realizar muchas operaciones de conjuntos o si tiene alguna operación de conjunto que dependa entre sí . ¡No solo eso, sino que setdown te permite escribir operaciones de set que dependen de otras operaciones de set!
En cualquier caso, creo que es genial y deberías echarle un vistazo.
fuente
Patrón de muestra para múltiples archivos (intersección en este caso):
Se expande a:
Archivos de prueba:
Salida:
fuente
Con
zsh
matrices (laszsh
matrices pueden contener cualquier secuencia arbitraria de bytes, incluso 0).(también tenga en cuenta que puede hacer
typeset -U array
para garantizar que sus elementos sean únicos).establecer membresía
(usando el
I
indicador de subíndice de matriz, para obtener el índice de la última aparición de$element
en la matriz (o 0 si no se encuentra). Eliminee
(parae
xact) para$element
que se tome como un patrón)${array:#pattern}
siendo una variación de ksh${var#pattern}
que elimina los elementos que coinciden con el patrón en lugar de simplemente eliminar la parte principal que coincide con el patrón. El(M)
(para coincidencia ) invierte el significado y elimina todos los elementos excepto los coincidentes (utilícelo$~element
para tomarlo como un patrón).establecer intersección
${set1:*set2}
hace la intersección de la matriz, pero la"${(@)...}"
sintaxis es necesaria para preservar elementos vacíosestablecer la igualdad
Comprueba si las matrices son idénticas (y en el mismo orden). El
q
indicador de expansión de parámetros cita los elementos (para evitar problemas con cosas comoa=(1 "2 3")
vsb=("1 2" 3)
), y los(j: :)
une con espacio antes de hacer una comparación de cadenas.Para verificar que tengan los mismos elementos, independientemente del orden, use la
o
bandera para ordenarlos. Vea también lau
bandera (única) para eliminar duplicados.establecer cardinalidad
prueba de subconjunto
Unión
(ver
typeset -U
arriba o elu
indicador de expansión de parámetros para tomar el caso de duplicados). Nuevamente, si la cadena vacía no es uno de los valores posibles, puede simplificar a:complemento
para los elementos de
$array1
que no están en$array2
.mínimo / máximo (comparación léxica)
mínimo / máximo (comparación de enteros decimales)
fuente