Intersección de matriz en bash

¿Cómo se comparan dos matrices en bash para encontrar todos los valores que se cruzan?

Digamos:
array1 contiene los valores 1 y 2
array2 contiene los valores 2 y 3

Debería volver 2 como resultado.

Mi propia respuesta, que aún no puedo publicar debido a su pequeña reputación:

for item1 in $array1; do for item2 in $array2; do if [[ $item1 = $item2 ]]; then result=$result" "$item1 fi done done 

Estoy buscando soluciones alternativas también.

Los elementos de la lista 1 se utilizan como expresión regular buscada en list2 (expresada como cadena: $ {list2 [*]}):

 list1=( 1 2 3 4 6 7 8 9 10 11 12) list2=( 1 2 3 5 6 8 9 11 ) l2=" ${list2[*]} " # add framing blanks for item in ${list1[@]}; do if [[ $l2 =~ " $item " ]] ; then # use $item as regexp result+=($item) fi done echo ${result[@]} 

El resultado es

 1 2 3 6 8 9 11 

Tomando la respuesta de @ Raihan y haciendo que funcione con archivos que no sean archivos (aunque se crean FD) Sé que es un poco engañoso, pero me pareció una buena alternativa

El efecto secundario es que la matriz de salida se clasificará lexicográficamente, espero que esté bien (tampoco sepa qué tipo de datos tiene, así que acabo de probar con números, puede haber trabajo adicional si necesita cadenas con caracteres especiales, etc.)

 result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort) <(for X in "${array2[@]}"; do echo "${X}"; done|sort))) 

Pruebas:

 $ array1=(1 17 33 99 109) $ array2=(1 2 17 31 98 109) result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort) <(for X in "${array2[@]}"; do echo "${X}"; done|sort))) $ echo ${result[@]} 1 109 17 

ps. Estoy seguro de que había una manera de sacar la matriz de un valor por línea sin el bucle for , simplemente lo olvido (¿IFS?)

Si se tratara de dos archivos (en lugar de matrices) que buscaba líneas que se cruzan, podría usar el comando comm .

 $ comm -12 file1 file2 

Su respuesta no funcionará, por dos razones:

  • $array1 simplemente se expande al primer elemento de array1 . (Al menos, en mi versión instalada de Bash es así como funciona. Eso no parece ser un comportamiento documentado, por lo que puede ser una peculiaridad dependiente de la versión).
  • Después de que se agrega el primer elemento al result , el result contendrá un espacio, por lo que la siguiente ejecución de result=$result" "$item1 se result=$result" "$item1 horrible. (En lugar de agregar al result , ejecutará el comando que consiste en los dos primeros elementos, y el result variable de entorno se establecerá en la cadena vacía.) Corrección: Resulta que estaba equivocado acerca de esto: la división de palabras no tener lugar dentro de las asignaciones. (Ver comentarios a continuación)

Lo que quieres es esto:

 result=() for item1 in "${array1[@]}"; do for item2 in "${array2[@]}"; do if [[ $item1 = $item2 ]]; then result+=("$item1") fi done done 

Ahora que entiendo lo que quiere decir con “matriz”, creo, en primer lugar, que debe considerar el uso de arreglos Bash reales. Son mucho más flexibles, ya que (por ejemplo) los elementos del conjunto pueden contener espacios en blanco, y puede evitar el riesgo de que * y ? activará la expansión del nombre de archivo.

Pero si prefiere usar su enfoque existente de cadenas delimitadas por espacios en blanco, entonces estoy de acuerdo con la sugerencia de RHT de usar Perl:

 result=$(perl -e 'my %array2 = map +($_ => 1), split /\s+/, $ARGV[1]; print join " ", grep $array2{$_}, split /\s+/, $ARGV[0] ' "$array1" "$array2") 

(Los saltos de línea son solo para facilitar la lectura; puede deshacerse de ellos si lo desea).

En el comando Bash anterior, el progtwig Perl incorporado crea un hash llamado %array2 contiene los elementos de la segunda matriz, y luego imprime cualquier elemento de la primera matriz que existe en %array2 .

Esto se comportará de forma ligeramente diferente a su código en la forma en que maneja los valores duplicados en la segunda matriz; en su código, si array1 contiene x dos veces y array2 contiene x tres veces, el result contendrá x seis veces, mientras que en mi código, el result contendrá x solo dos veces. No sé si eso importa, ya que no conozco sus requisitos exactos.