Цикл BASH while для проверки строк в файле отображается слишком много раз

Я пишу скрипт, в котором хочу взять каждую строку из файла и проверить совпадение в другом файле. Если я найду совпадение, я хочу сказать, что я нашел совпадение, а если нет, то сказать, что я не нашел совпадения.

2 файла содержат хэши md5. Старый файл является исходным, а новый файл предназначен для проверки наличия каких-либо изменений по сравнению с исходным файлом.

исходный файл: chksum новый файл: chksum1

#!/bin/bash

while read e; do
     while read f; do
     if [[ $e = $f ]]
     then 
     echo $e "is the same"
     else
          if [[ $e != $f]]
          then
          echo $e "has been changed"
          fi
     fi
     done < chksum1
done < chksum

Моя проблема в том, что для файлов, которые были изменены, я получаю эхо каждый раз, когда выполняется проверка в цикле, и я хочу, чтобы он отображал файл только один раз и говорил, что он не найден.

Надеюсь, это понятно.


person zacgalf    schedule 13.06.2013    source источник
comment
Можете ли вы опубликовать образец из вашего файла? ИМО awk может сделать это лучше.   -  person jaypal singh    schedule 14.06.2013
comment
Почему вы не хотите использовать diff? diff chksum chksum1 сделает именно то, что вы хотите.   -  person Nikolai Popov    schedule 14.06.2013
comment
Небольшое дополнение: В части else не нужно проверять, отличаются ли значения, потому что они точно есть. Просто повторите строку.   -  person TrueY    schedule 14.06.2013
comment
+1! Спасибо за вопрос! Я снова чему-то научился. Я прочитал man bash (снова) и обнаружил, что ${var:+val} и ${var+val} ведут себя по-разному!   -  person TrueY    schedule 14.06.2013
comment
Я пытался использовать diff, но мне было трудно, так как я должен сказать, какие файлы были отредактированы, а какие нет. diff показал мне все файлы и после перебора вариантов я решил использовать цикл   -  person zacgalf    schedule 14.06.2013
comment
@someguy Вы правы. Сохранение простоты не похоже на карты здесь. Я разместил решение с sort и uniq, но diff работает так же хорошо, если не лучше.   -  person Samveen    schedule 14.06.2013
comment
@zacgalf Что не так с diff с опцией -q?   -  person Nikolai Popov    schedule 14.06.2013


Ответы (6)


вы можете использовать тот же сценарий, но поставить напоминание.

#!/bin/bash

while read e; do
    rem=0
        while read f; do
        if [[ $e = $f ]]
        then 
            rem=1
        fi
        done < chksum1
    if [[ rem = 1 ]] 
    then
        echo $e "is the same"
    else
        echo $e "has been changed"
    fi
done < chksum

Это должно работать правильно

person Franko    schedule 13.06.2013

Вы были очень близки. Это будет работать:

while read e; do
     while read f; do
     found=0
     if [[ $e = $f ]]
     then 
         # echo $e "is the same"
         found=1
         break
     fi
     done < chksum1
     if [ $found -ne 0 ]
     then
        echo "$e is the the same"
     else
        echo "$e has been changed"
     fi
done < chksum
person cforbish    schedule 13.06.2013
comment
Я не уверен, почему, потому что ваш сценарий мне понятен, но он говорит мне, что все файлы были изменены. - person zacgalf; 14.06.2013

Немного упрощенная версия, позволяющая избежать многократного чтения одного и того же файла (bash 4.0 и выше). Я предполагаю, что файлы содержат уникальные имена файлов, а формат файла является результатом md5sum команда.

#!/bin/bash

declare -A hash
while read md5 file; do hash[$file]=$md5; done <chksum
while read md5 file; do
  [ -z "${hash[$file]}" ] && echo "$file new file" && continue
  [ ${hash[$file]} == $md5 ] && echo "$file is same" && continue
  echo "$file has been changed"
done <chksum1

Этот скрипт считывает первый файл в ассоциативный массив с именем hash. Индекс — это имя файла, а значение — контрольная сумма MD5. Второй цикл считывает второй файл контрольной суммы; имени файла нет в hash, он печатает file new file; если он находится в hash и значение равно, то это один и тот же файл; если не равно пишет file has been changed.

Входные файлы:

$ cat chksum
eed0fc0313f790cec0695914f1847bca  ./a.txt
9ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./c.txt
$ cat chksum1
eed0fc0313f790cec0695914f1847bca  ./a.txt
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt

Выход:

./a.txt is same
./b.txt has been changed
./d.txt new file

РАСШИРЕННАЯ ВЕРСИЯ

Также обнаруживать удаленные файлы.

#!/bin/bash

declare -A hash
while read md5 file; do hash[$file]=$md5; done <chksum
while read md5 file; do
  [ -z "${hash[$file]}" ] && echo "$file new file" && continue
  if [ ${hash[$file]} == $md5 ]; then echo "$file is same"
  else echo "$file has been changed"
  fi
  unset hash[$file]
done <chksum1
for file in ${!hash[*]};{ echo "$file deleted file";}

Выход:

./a.txt is same
./b.txt has been changed
./d.txt new file
./c.txt deleted file
person TrueY    schedule 13.06.2013
comment
Это немного впереди меня, но я запущу его и изучу - person zacgalf; 14.06.2013
comment
Я предполагал, что если я изменю md5 на переменную пользовательского ввода, она будет работать для sha1, sha512 и т. Д.? - person zacgalf; 14.06.2013
comment
@BrantNanton: добавлено некоторое объяснение. Вам не нужно менять входную переменную, это просто имя. Вам нужно создать файлы с правильными контрольными суммами. Если первый столбец — это контрольная сумма, а второй — имя файла, вам не нужно ничего менять. - person TrueY; 14.06.2013
comment
@BrantNanton: я видел ваш скрипт, и этот ответ должен работать с ним при любом расчете контрольной суммы, если первый столбец - это контрольная сумма, а второй - имя файла. - person TrueY; 14.06.2013
comment
Спасибо большое, буду тестить - person zacgalf; 14.06.2013
comment
Я ошибка. hash[$file]: неправильный индекс массива. это на первой строчке. - person zacgalf; 14.06.2013
comment
@zacgalf: какая у тебя bash версия? Ассоциативные массивы поддерживаются только в bash 4.0 и выше. В какой строке добавить лишний []? - person TrueY; 14.06.2013
comment
@zacgalf: я снова протестировал оба скрипта на 4.1.10, и они отлично работают. На 3.2.25 перестает говорить: ./a.sh: line 15: declare: -A: invalid option. - person TrueY; 14.06.2013

Я хотел бы предложить альтернативное решение: как насчет того, чтобы вы не читали построчно, а использовали sort и uniq -c, чтобы увидеть, есть ли различия. Нет необходимости в петле, где простая труба может сделать вашу работу.

В этом случае вам нужны все строки, которые изменились в файле chksum1, поэтому

sort chksum chksum1 chksum1 | uniq -c | egrep '^\s+2\s' | sed 's%\s\+2\s%%'

Это также читает chksum1 только 2 раза, по сравнению с примером на основе цикла, который считывает его один раз на строку chksum.

Повторное использование входных файлов из одного из других ответов:

samveen@precise:~/so$ cat chksum
eed0fc0313f790cec0695914f1847bca  ./a.txt
9ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./c.txt

samveen@precise:~/so$ cat chksum1
eed0fc0313f790cec0695914f1847bca  ./a.txt
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt

samveen@precise:~/so$ sort chksum chksum1 chksum1 |uniq -c | egrep '^\s+2\s' |sed 's%\s\+2\s%%'
8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
a91a408e113adce865cba3c580add827  ./d.txt

Другое возможное решение (как предлагается в комментариях к вопросу) использовать diff в сочетании с sort:

diff <(sort chksum) <(sort chksum1) |grep '^>'

Выход:

samveen@precise:~/so$ diff <(sort chksum) <(sort chksum1) |grep '^>'
> 8ee9e1fffbb3c16357bf80c6f7a27574  ./b.txt
> a91a408e113adce865cba3c580add827  ./d.txt
person Samveen    schedule 14.06.2013

Простое решение:

diff -q chksum1 chksum
person Nikolai Popov    schedule 14.06.2013

Как насчет использования команды grep. Каждая строка, которую вы читаете из chksum, будет служить шаблоном поиска в chksum1. Если grep находит совпадение, "$?", который содержит возвращаемое значение grep, будет равен 0, в противном случае он будет равен 1.

while read e; do  
  grep $e checksum1
  if[ $? == "0" ];then
     echo $e "is the same"
  else
     echo $e "has been changed"
  fi
done < chksum
person Debugger    schedule 14.06.2013