Phương pháp 1: sử dụng những gì bạn biết
Vì bạn đã biết cách lặp qua một tệp, bạn có thể kết hợp các tệp và sau đó xử lý các tệp kết hợp. Lệnh paste
nối hai tệp theo từng dòng. Nó đặt một tab giữa các dòng đến từ hai tệp, vì vậy giải pháp này giả định rằng không có tab nào trong tên tệp của bạn. (Bạn có thể thay đổi dấu phân cách nhưng bạn phải tìm một ký tự không có trong tên tệp.)
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
Nếu bạn muốn bỏ qua các dòng trống, bạn cần phải làm riêng từng tệp, vì paste
có thể khớp một dòng trống từ một tệp với một dòng không trống từ một tệp khác. Bạn có thể sử dụng grep
để lọc các dòng không trống.
paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
…
Lưu ý rằng nếu hai tệp có độ dài khác nhau, bạn sẽ nhận được một sản phẩm nào $file2
(bất kể danh sách nào kết thúc trước).
Phương pháp 2: lặp qua hai tệp
Bạn có thể đặt một lệnh phức tạp như bạn muốn trong điều kiện của vòng lặp while. Nếu bạn đặt read file1 <&3 && read file2 <&4
thì vòng lặp sẽ chạy miễn là cả hai tệp có một dòng để đọc, tức là cho đến khi một tệp hết.
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3<list1..txt 4<list2.txt
Nếu bạn muốn bỏ qua các dòng trống, nó phức tạp hơn một chút, vì bạn phải bỏ qua hai tệp một cách độc lập. Cách dễ dàng là chia vấn đề thành hai phần: bỏ qua các dòng trống từ một tệp và xử lý các dòng không trống. Một phương pháp để bỏ qua các dòng trống là xử lý thông qua grep
như trên. Coi chừng không gian cần thiết giữa <
toán tử chuyển hướng và <(
lệnh bắt đầu một lệnh điều chỉnh.
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")
Một phương pháp khác là viết một hàm hoạt động như thế read
nhưng bỏ qua các dòng trống. Chức năng này có thể hoạt động bằng cách gọi read
trong một vòng lặp. Nó không phải là một hàm, nhưng một hàm là cách tiếp cận tốt nhất, cả để tổ chức mã của bạn và bởi vì đoạn mã đó cần phải được gọi hai lần. Trong hàm, ${!#}
là một thể hiện của cấu trúc bash ${!VARIABLE}
ước tính giá trị của biến có tên là giá trị của VARIABLE
; ở đây biến là biến đặc biệt #
chứa số lượng tham số vị trí, vì vậy ${!#}
là tham số vị trí cuối cùng.
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
.