Bash: Iterando 2 listas usando un solo bucle For In

Bash: Iterando 2 listas usando un solo bucle For In

Supongamos que tengo 2 bucles separados

for file1 in `ls Dir1/` ; do
    echo $file1
done

for file2 in `ls Dir2/` ; do
    echo $file2
done

Quiero que un bucle único itere el pseudocódigo de ambos directorios.

for file1 , file2 in `ls Dir1` , `ls Dir2`
do
    echo $file1
    echo file2
done

Es posible

Respuesta1

Un whilebucle con una entrada adecuada puede hacer el trabajo, suponiendo que no haya caracteres de nueva línea en los nombres de los archivos.

paste -d/ <(ls /var) <(ls /usr) |
  while IFS=/ read -r e u; do
    printf '%s\n' "$e $u"
  done

Respuesta2

shopt -s nullglob

dir1names=( Dir1/* )
dir2names=( Dir2/* )

while [ "${#dir1names[@]}" -gt 0 ] &&
      [ "${#dir2names[@]}" -gt 0 ]
do

    printf '%s\n' "${dir1names[0]##*/}"
    printf '%s\n' "${dir2names[0]##*/}"

    dir1names=( "${dir1names[@]:1}" )
    dir2names=( "${dir2names[@]:1}" )
done

Esto se utiliza bashpara obtener todos los nombres de ruta de cada directorio en dos matrices. Luego imprime la parte del nombre de archivo de estos nombres de ruta (como lslo haría), alternando entre las matrices, y elimina los elementos completos impresos de las matrices. Se detiene cuando una de las matrices está completamente vacía.

La nullglobopción Shell hace que los patrones globales no coincidentes se expandan hasta quedar en nada en lugar de permanecer sin expandir.

Pruebas:

$ tree
.
|-- Dir1
|   |-- file-1
|   |-- file-2
|   |-- file-3
|   `-- file-4
|-- Dir2
|   |-- otherfile-1
|   |-- otherfile-2
|   |-- otherfile-3
|   |-- otherfile-4
|   |-- otherfile-5
|   `-- otherfile-6
`-- script.sh

2 directories, 11 files
$ bash script.sh
file-1
otherfile-1
file-2
otherfile-2
file-3
otherfile-3
file-4
otherfile-4

Si esto esde hechoacerca de emparejar archivos según sus nombres, de modo que un archivo en un directorio se empareje con el archivo correspondiente en otro (como parece que a veces se hace, por ejemplo, en aplicaciones bioinformáticas), entonces es mejor simplemente iterar sobre uno de los conjuntos y luegoconstruyendoel nombre de los archivos correspondientes del otro conjunto.

Suponiendo que se llaman los archivos something_R1_morey something_R2_moredónde somethingse moreidentifica un par de archivos R1en particular.R2

for r1 in dir1/*_R1_*; do
    r2=${r1##*/}              # dir1/something_R1_more --> something_R1_more
    r2=dir2/${r2/_R1_/_R2_}   # something_R1_more      --> dir2/something_R2_more

    if [ ! -f "$r2" ]; then
        printf '%s not found\n' "$r2" >&2
        exit 1
    fi

    # process "$r1" and "$r2" here
done

Respuesta3

tu generalmenteno quiero analizar la salida dels.

Aquí, con zsh(ya estás usando zshla sintaxis, no bashporque no estás citando tus variables y usando la sustitución de comandos sin deshabilitar el globbing), podrías hacer:

dir1_file_names=(dir1/*(N:t))
dir2_file_names=(dir2/*(N:t))
for f1 f2 (${dir1_file_names:^dir2_file_names})
  printf '%s\n' "f1: $f1, f2: $f2"

zshPuede realizar un bucle con varias variables. ${a:^b}es uncompresión de matricesoperador. Si uno de los arrays tiene menos elementos que el otro, será como si estuvieran truncados a la longitud del más pequeño.

Vea también sus operadores de intersección y resta de matrices si se trata de comparar los nombres de archivos en los dos directorios:

file_names_in_both_dir1_and_dir2=(${dir1_file_names:*dir2_file_names})
file_names_only_in_dir1=(${dir1_file_name:|dir2_file_names})
file_names_only_in_dir2=(${dir2_file_name:|dir1_file_names})

Respuesta4

La salida de múltiples variables se puede guardar en una sola variable como se menciona a continuación. Comprueba si te funciona

#!/bin/bash
cd /
for file1 in $(ls /usr/ ; echo "::::::NEXT:::::::" ; ls /sys/)
do
    echo $file1
done

información relacionada