Проведіть паралельно рядки двох файлів паралельно [закрито]


18

Завданням сценарію, який я створюю, є порівняння двох серій файлів. Імена файлів самі зберігаються у двох окремих файлах, по одному шляху в рядку. Моя ідея - мати дві while readпетлі, по одній для кожного списку імен файлів, але як я можу змішати дві петлі разом?

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

Мені потрібно вміти порівнювати файли з двох різних списків одночасно через два цикли читання ... Чи це можливо навіть?


Ви маєте намір зробити цей сценарій як короля викликів? Якщо це не так, то вже існують потужні інструменти для порівняння файлів, наприклад diff.
lgeorget

" вид виклику", вибачте
lgeorget

@lgeorget ОП використовує diff.
terdon

ах, файли з двох списків. Вибачте за марні коментарі ...
lgeorget

Будь ласка, уникайте перехресного опублікування
iruvar

Відповіді:


20

Вам не потрібно дві петлі; вам просто потрібно прочитати з двох файлів в одному циклі.

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

ось набагато менше коду дякую! як я можу обробляти виключення порожнього рядка одночасно, а потім для двох циклів?
mkrouse

@mkrouse, я не знаю, що ви робили з цією змінною $ server там раніше, але проте ви перевіряєте наявність порожньої рядка на одній змінній, ви просто робите те саме на іншій ...
psusi

7

Спосіб 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

Мені подобається використання -uваріанту читання
Феліпе Альварес

1

Одним із підходів було б використовувати read -raзамість просто read. Якщо припустити , що filestoCompare.txtмістяться 2 колонки з іменами файлів в кожній, то read -raпрочитав би обидві колонки в той же час і призначити їх в масив, compareFile. Потім до цього масиву можна отримати доступ, щоб індекс 0 був першим файлом, а індекс 1 - другим файлом кожного разу через whileцикл.

Приклад

Скажіть, у мене є цей файл: filestoCompare.txtі він містить таке:

file1 file2
file3 file4
file5 file6

Команда пройти через цей файл буде наступною:

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

Якщо два файли справді є окремими файлами, такими як:

#list1
file1
file2
file3

#list2
file4
file5
file6

Їх можна з'єднати разом із pasteкомандою так:

$ paste list1 list2 > list1and2

Ось зміст list1and2:

$ cat list1and2
file1   file4
file2   file5
file3   file6

Але це не вхідний формат: списки складаються у двох різних файлах. Ви могли joinїх першими.
Жил "ТАК - перестань бути злим"

@Gilles - Я знаю, що це не вхідний формат, я вважаю, що я навіть сказав, що "... Якщо припустимо, що файлstoCompare.txt містив 2 стовпчики з іменами файлів у кожному ...". Я розумію вашу суперечку і не погоджуюся. ОП не надала жодних додаткових вказівок з цього питання з моменту опублікування.
slm

@Gilles - що робити, якщо я додаю приклад, який показує, як використовувати команду pasteдля приєднання до двох файлів? Чи змусить вас це скасувати?
slm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.