¿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 -dno 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
commpuede usarse para hacer eso, tratando cada línea como un miembro fijo:-12por intersección,-13por diferencia. (Y-23le da una diferencia invertida, es decir, enset2 - set1lugar deset1 - set2). Union estásort -uen 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 osLa 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 setopAquí 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 2Las consultas booleanas solo se devuelven
EXIT_SUCCESSen caso de ser verdaderas, yEXIT_FAILUREtambié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\fo 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
--counttodos los elementos del conjunto de salida,--trimtodos los elementos de entrada (es decir, borrar todos los caracteres anteriores y posteriores no deseados como espacio, coma, etc.)--include-empty,--ignore-case,--output-separatorelementos entre la secuencia de salida (el valor predeterminado es\n),Visite
man setopo 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,
greppuede 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 namey 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
zshmatrices (laszshmatrices pueden contener cualquier secuencia arbitraria de bytes, incluso 0).(también tenga en cuenta que puede hacer
typeset -U arraypara garantizar que sus elementos sean únicos).establecer membresía
(usando el
Iindicador de subíndice de matriz, para obtener el índice de la última aparición de$elementen la matriz (o 0 si no se encuentra). Eliminee(paraexact) para$elementque 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$~elementpara 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
qindicador 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
obandera para ordenarlos. Vea también laubandera (única) para eliminar duplicados.establecer cardinalidad
prueba de subconjunto
Unión
(ver
typeset -Uarriba o eluindicador 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
$array1que no están en$array2.mínimo / máximo (comparación léxica)
mínimo / máximo (comparación de enteros decimales)
fuente