Erstens, lesen Sie keine Zeilen mit for , da es einige unvermeidbare Probleme beim Lesen von Zeilen durch Wortteilung gibt.
Wenn Sie Dateien gleicher Länge annehmen oder nur eine Schleife ausführen möchten, bis die kürzere von zwei Dateien gelesen wurde, ist eine einfache Lösung möglich.
while read -r x && read -r y <&3; do
...
done <file1 3<file2
Es ist schwierig, eine allgemeinere Lösung zusammenzustellen, da die read
Rückgabe falsch ist und mehrere andere Gründe vorliegen. In diesem Beispiel kann eine beliebige Anzahl von Streams gelesen und nach der kürzesten oder längsten Eingabe zurückgegeben werden.
#!/usr/bin/env bash
# Open the given files and assign the resulting FDs to arrName.
# openFDs arrname file1 [file2 ...]
openFDs() {
local x y i arr=$1
[[ -v $arr ]] || return 1
shift
for x; do
{ exec {y}<"$x"; } 2>/dev/null || return 1
printf -v "${arr}[i++]" %d "$y"
done
}
# closeFDs FD1 [FD2 ...]
closeFDs() {
local x
for x; do
exec {x}<&-
done
}
# Read one line from each of the given FDs and assign the output to arrName.
# If the first argument is -l, returns false only when all FDs reach EOF.
# readN [ -l ] arrName FD1 [FD2 ...]
readN() {
if [[ $1 == -l ]]; then
local longest
shift
else
local longest=
fi
local i x y status arr=$1
[[ -v $arr ]] || return 1
shift
for x; do
if IFS= read -ru "$x" "${arr}[i]" || { unset -v "${arr}[i]"; [[ ${longest+_} ]] && return 1; }; then
status=0
fi
((i++))
done
return ${status:-1}
}
# readLines file1 [file2 ...]
readLines() {
local -a fds lines
trap 'closeFDs "${fds[@]}"' RETURN
openFDs fds "$@" || return 1
while readN -l lines "${fds[@]}"; do
printf '%-1s ' "${lines[@]}"
echo
done
}
{
readLines /dev/fd/{3..6} || { echo 'error occured' >&2; exit 1; }
} <<<$'a\nb\nc\nd' 3<&0 <<<$'1\n2\n3\n4\n5' 4<&0 <<<$'x\ny\nz' 5<&0 <<<$'7\n8\n9\n10\n11\n12' 6<&0
# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:
Also je nachdem, ob es readN
geht -l
, ist die Ausgabe entweder
a 1 x 7
b 2 y 8
c 3 z 9
d 4 10
5 11
12
oder
a 1 x 7
b 2 y 8
c 3 z 9
Das Lesen mehrerer Streams in einer Schleife, ohne alles in mehreren Arrays zu speichern, ist nicht allzu häufig. Wenn Sie nur Arrays lesen möchten, sollten Sie einen Blick darauf werfen mapfile
.
||
funktioniert bei mir nicht Es verarbeitet Datei1 dann Datei2 , aber es hält die Dateien synchronisiert&&
, wodurch die while- Schleife beim ersten Mal beendet wird . - GNU Bash 4.1.5