Bash: Iterieren von 2 Listen mit einer einzelnen For In-Schleife

Bash: Iterieren von 2 Listen mit einer einzelnen For In-Schleife

Angenommen, ich habe 2 separate Schleifen

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

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

Ich möchte eine einzelne Schleife, um beide Verzeichnisse Pseudocode zu iterieren

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

Ist es möglich

Antwort1

Eine whileSchleife mit geeigneter Eingabe kann die Aufgabe erledigen, vorausgesetzt, die Dateinamen enthalten keine Zeilenumbruchzeichen.

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

Antwort2

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

Dies dient bashdazu, alle Pfadnamen aus jedem Verzeichnis in zwei Arrays zu übertragen. Anschließend wird der Dateinamenteil dieser Pfadnamen (wie lsüblich) abwechselnd zwischen den Arrays gedruckt und die gedruckten Einträge aus den Arrays gelöscht. Es wird beendet, wenn eines der Arrays vollständig leer ist.

Die nullglobShell-Option bewirkt, dass nicht übereinstimmende Globbing-Muster ins Leere expandiert werden, anstatt unerweitert zu bleiben.

Testen:

$ 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

Wenn das istGenau genommenüber das Paaren von Dateien nach ihren Namen, so dass eine Datei in einem Verzeichnis mit der entsprechenden Datei in einem anderen gepaart wird (wie es manchmal in z. B. Bioinformatik-Anwendungen gemacht wird, scheint es), dann ist es besser, einfach über einen der Sätze zu iterieren und dannkonstruierender Name der entsprechenden Dateien aus dem anderen Set.

Angenommen, die Dateien heißen something_R1_moreund geben something_R2_moredort den Namen an somethingund moreidentifizieren ein bestimmtes R1Dateipaar 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

Antwort3

Sie im Allgemeinenmöchte die Ausgabe nicht analysieren vonls.

Hier könnten Sie mit zsh(Sie verwenden bereits zshSyntax, nicht bashweil Sie Ihre Variablen nicht in Anführungszeichen setzen und Befehlsersetzung verwenden, ohne Globbing zu deaktivieren) Folgendes tun:

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"

zshkann mit mehreren Variablen schleifen. ${a:^b}ist einArray-KomprimierungOperator. Wenn eines der Arrays weniger Elemente als das andere hat, ist es so, als wären sie auf die Länge des kleinsten Elements gekürzt.

Siehe auch die Array-Schnittpunkt- und Subtraktionsoperatoren, wenn es um den Vergleich der Dateinamen in den beiden Verzeichnissen geht:

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

Antwort4

Die Ausgabe mehrerer Variablen kann in einer einzigen Variable gespeichert werden, wie unten beschrieben. Überprüfen Sie, ob es für Sie funktioniert

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

verwandte Informationen