Во-первых, не читайте строки с помощью for , так как есть несколько неизбежных проблем с чтением строк с помощью разделения слов.
Предполагая, что файлы равной длины, или если вы хотите зацикливаться только до тех пор, пока не будет прочитано более короткое из двух файлов, возможно простое решение.
while read -r x && read -r y <&3; do
...
done <file1 3<file2
Составить более общее решение сложно из-за того, что read
возвращает false, и по нескольким другим причинам. В этом примере можно прочитать произвольное количество потоков и вернуться после самого короткого или самого длинного ввода.
#!/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:
Таким образом, в зависимости от того, readN
получает ли -l
, либо
a 1 x 7
b 2 y 8
c 3 z 9
d 4 10
5 11
12
или
a 1 x 7
b 2 y 8
c 3 z 9
Необходимость читать несколько потоков в цикле без сохранения всего в несколько массивов не так уж часто. Если вы просто хотите читать массивы, вы должны посмотреть mapfile
.
||
не работает для меня Он обрабатывает file1 затем file2 , но это сохранить файлы синхронизируются с&&
, который выходит из то время как цикл по первому EOF . - GNU bash 4.1.5