Bash: Iterando 2 listas usando um único loop For In

Bash: Iterando 2 listas usando um único loop For In

Suponha que eu tenha 2 loops separados

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

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

Quero que o loop único itere o pseudocódigo de ambos os diretórios

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

É possível

Responder1

Um whileloop com entrada adequada pode fazer o trabalho, assumindo que não há caracteres de nova linha nos nomes dos arquivos.

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

Responder2

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

Isso é usado bashpara obter todos os nomes de caminhos de cada diretório em duas matrizes. Em seguida, ele imprime a parte do nome do arquivo desses nomes de caminho (como lsfaria), alternando entre as matrizes, e exclui os inteiros impressos das matrizes. Ele para quando um dos arrays está completamente vazio.

A nullglobopção shell faz com que os padrões globais não correspondentes se expandam para nada, em vez de permanecerem sem expansão.

Teste:

$ 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

Se isso éna verdadesobre emparelhar arquivos de acordo com seus nomes, de modo que um arquivo em um diretório seja emparelhado com o arquivo correspondente em outro (como às vezes é feito, por exemplo, em aplicativos de bioinformática, ao que parece), então é melhor apenas iterar sobre um dos conjuntos e entãoconstruindoo nome dos arquivos correspondentes do outro conjunto.

Supondo que os arquivos sejam chamados something_R1_moree something_R2_moreonde somethinge moreesteja identificando um determinado R1par R2de arquivos.

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

Responder3

Você geralmentenão quero analisar a saída dels.

Aqui, com zsh(você já está usando zshsintaxe, não bashporque não está citando suas variáveis ​​​​e usando substituição de comando sem desabilitar globbing), você poderia fazer:

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"

zshpode fazer um loop com diversas variáveis. ${a:^b}é umcompactação de arrayoperador. Se um dos arrays tiver menos elementos que o outro, será como se eles estivessem truncados no comprimento do menor.

Veja também seus operadores de interseção e subtração de array se for para comparar os nomes dos arquivos nos dois diretórios:

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})

Responder4

A saída de múltiplas variáveis ​​pode ser salva em uma única variável, conforme mencionado abaixo. Verifique se funciona para você

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

informação relacionada