Способ 1: используйте то, что вы знаете
Поскольку вы уже знаете, как перебрать один файл, вы можете объединить файлы и затем обработать объединенные файлы. Команда paste
объединяет два файла построчно. Он помещает вкладку между строками из двух файлов, поэтому в этом решении предполагается, что в именах файлов нет вкладок. (Вы можете изменить разделитель, но вы должны найти символ, которого нет в имени файла.)
paste -- "$list1.txt" "list2.txt" |
while IFS=$'\t' read -r file1 file2 rest; do
diff -q -- "$file1" "$file2"
case $? in
0) status='same';;
1) status='different';;
*) status='ERROR';;
esac
echo "$status $file1 $file2"
done
Если вы хотите пропустить пустые строки, вам нужно сделать это в каждом файле отдельно, так как paste
может совпадать пустая строка из одного файла с непустой строкой из другого файла. Вы можете использовать grep
для фильтрации непустых строк.
paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
…
Обратите внимание, что если два файла имеют разную длину, вы получите пустой $file2
(независимо от того, какой список закончился первым).
Способ 2: зациклить два файла
Вы можете поместить любую сложную команду в состояние цикла while. Если вы поставите, read file1 <&3 && read file2 <&4
цикл будет выполняться до тех пор, пока оба файла будут иметь строку для чтения, т.е. пока не закончится один файл.
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3<list1..txt 4<list2.txt
Если вы хотите пропустить пустые строки, это немного сложнее, потому что вы должны пропустить два файла независимо друг от друга. Самый простой способ - разбить проблему на две части: пропустить пустые строки из одного файла и обработать непустые строки. Один из способов пропустить пустые строки - обработать, grep
как описано выше. Следите за тем, чтобы между <
оператором перенаправления и тем <(
, кто запускает команду, появилось свободное пространство.
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")
Другой метод заключается в написании функции, которая ведет себя как, read
но пропускает пустые строки. Эта функция может работать, вызывая read
в цикле. Это не обязательно должна быть функция, но функция - лучший подход, как для организации вашего кода, так и потому, что этот фрагмент кода необходимо вызывать дважды. В функции ${!#}
это экземпляр конструкции bash, ${!VARIABLE}
которая оценивает значение переменной, имя которой равно значению VARIABLE
; здесь переменная является специальной переменной, #
которая содержит номер позиционного параметра, так же ${!#}
как и последний позиционный параметр.
function read_nonblank {
while read "$@" &&
[[ ${!#} !~ [^[:space:]] ]]
do :; done
}
while read_nonblank -u 3 -r file1 && read_nonblank -u 4 -r file2; do
…
done 3<list1..txt 4<list2.txt
diff
.