Loop melalui baris dua file secara paralel [ditutup]

18

Objek skrip yang saya buat adalah untuk membandingkan dua seri file. Nama file itu sendiri disimpan ke dalam dua file terpisah, satu jalur per baris. Ide saya adalah memiliki dua while readloop, satu untuk setiap daftar nama file, tetapi bagaimana saya bisa mencampur dua loop bersama-sama?

while read compareFile <&3; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile" _(other file from loop?_) >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt

Saya harus dapat membandingkan file dari dua daftar yang berbeda secara bersamaan melalui dua saat membaca loop ... Apakah ini mungkin?

mkrouse
sumber
Apakah Anda ingin menjadikan naskah ini sebagai raja tantangan? Jika tidak, alat yang ampuh sudah ada untuk membandingkan file, seperti diff.
lororget
" agak tantangan", maaf
lgeorget
@ lororget OP gunakan diff.
terdon
ah, file dari dua daftar. Maaf atas komentar yang tidak berguna ...
lgeorget
Harap hindari posting silang
iruvar

Jawaban:

20

Anda tidak perlu dua loop; Anda hanya perlu membaca dari dua file dalam satu loop.

while read compareFile1 <&3 && read compareFile2 <&4; do     
 if [[ ! $server =~ [^[:space:]] ]] ; then  #empty line exception
    continue
 fi   
    echo "Comparing file - $compareFile"
 if diff "$compareFile1" "$compareFile2" >/dev/null ; then
     echo Same
 else
      echo Different
 fi 
done 3</infanass/dev/admin/filestoCompare.txt 4<other_file
psusi
sumber
lebih banyak kode kurang terima kasih! bagaimana cara menangani pengecualian baris kosong pada saat yang sama maka untuk dua loop?
mkrouse
@mkrouse, saya tidak tahu apa yang Anda lakukan dengan variabel $ server di sana sebelumnya, tetapi bagaimana pun Anda menguji baris kosong pada satu variabel, Anda hanya melakukan hal yang sama pada yang lain ...
psusi
7

Metode 1: gunakan apa yang Anda ketahui

Karena Anda sudah tahu cara melompati satu file, Anda dapat menggabungkan file dan kemudian memproses file gabungan. Perintah tersebut pastemenggabungkan dua file baris demi baris. Ini menempatkan tab di antara garis yang berasal dari dua file, jadi solusi ini mengasumsikan bahwa tidak ada tab di nama file Anda. (Anda dapat mengubah pemisah tetapi Anda harus menemukan karakter yang tidak ada dalam nama file.)

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

Jika Anda ingin melewati baris kosong, Anda harus melakukannya di setiap file secara terpisah, karena pastemungkin cocok dengan baris kosong dari satu file dengan baris non-kosong dari file lain. Anda dapat menggunakan grepuntuk menyaring garis yang tidak kosong.

paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
  

Perhatikan bahwa jika kedua file memiliki panjang yang berbeda, Anda akan mendapatkan yang kosong $file2(terlepas dari daftar mana yang berakhir lebih dulu).

Metode 2: loop dua file

Anda dapat menempatkan perintah yang kompleks seperti yang Anda inginkan dalam kondisi loop sementara. Jika Anda meletakkan read file1 <&3 && read file2 <&4maka loop akan berjalan selama kedua file memiliki satu baris untuk dibaca, yaitu sampai satu file habis.

while read -u 3 -r file1 && read -u 4 -r file2; do
  
done 3<list1..txt 4<list2.txt

Jika Anda ingin melompati garis kosong, ini sedikit lebih rumit, karena Anda harus melompati dua file secara mandiri. Cara mudah adalah memecah masalah menjadi dua bagian: lewati baris kosong dari satu file, dan proses baris yang tidak kosong. Salah satu metode untuk melewati garis kosong adalah dengan memproses grepseperti di atas. Waspadai ruang yang diperlukan antara <operator pengalihan dan <(yang memulai susbtitusi perintah.

while read -u 3 -r file1 && read -u 4 -r file2; do
  
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")

Metode lain adalah menulis fungsi yang berperilaku seperti readtetapi melompati garis kosong. Fungsi ini dapat bekerja dengan memanggil readsatu lingkaran. Itu tidak harus menjadi fungsi, tetapi fungsi adalah pendekatan terbaik, baik untuk mengatur kode Anda dan karena potongan kode itu perlu dipanggil dua kali. Dalam fungsinya, ${!#}adalah turunan dari bash construct ${!VARIABLE}yang mengevaluasi nilai dari variabel yang namanya adalah nilai VARIABLE; di sini variabelnya adalah variabel khusus #yang berisi jumlah parameter posisi, demikian ${!#}juga parameter posisi terakhir.

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
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya suka penggunaan -uopsi baca
Felipe Alvarez
1

Salah satu pendekatan adalah menggunakan, read -rabukan hanya read. Dengan asumsi filestoCompare.txt2 kolom yang terkandung dengan nama file di masing-masing, read -raakan membaca kedua kolom pada saat yang sama dan menetapkannya ke dalam array compareFile,. Array ini kemudian dapat diakses sehingga indeks 0 akan menjadi file pertama dan indeks 1 akan menjadi file ke-2 setiap kali melalui whileloop.

Contoh

Katakanlah saya punya file ini:, filestoCompare.txtdan ini berisi yang berikut:

file1 file2
file3 file4
file5 file6

Perintah untuk membuka file ini adalah sebagai berikut:

$ while read -ra a ; do printf "%s\t%s\n" ${a[0]} ${a[1]}; done < filestoCompare.txt
file1   file2
file3   file4
file5   file6

Jika 2 file tersebut memang file yang terpisah seperti:

#list1
file1
file2
file3

#list2
file4
file5
file6

Mereka dapat bergabung bersama dengan pasteperintah seperti ini:

$ paste list1 list2 > list1and2

Berikut isi list1and2:

$ cat list1and2
file1   file4
file2   file5
file3   file6
slm
sumber
Tapi itu bukan format input: daftar ada di dua file berbeda. Anda bisa joinmelakukannya dulu.
Gilles 'SO- berhenti bersikap jahat'
@Gilles - Saya tahu itu bukan format input, saya yakin saya bahkan mengatakan bahwa "... Dengan asumsi filestoCompare.txt berisi 2 kolom dengan nama file di masing-masing ...". Saya mengerti pendapat Anda dan tidak setuju. OP belum memberikan panduan lebih lanjut tentang pertanyaan ini sejak mempostingnya.
slm
@Gilles - bagaimana jika saya menambahkan contoh yang menunjukkan cara menggunakan perintah pasteuntuk bergabung dengan 2 file? Apakah itu akan membuat Anda undownvote?
slm