У меня есть сценарий оболочки, в котором мне нужно проверить, являются ли два файла одинаковыми или нет. Я делаю это для большого количества файлов, и в моем сценарии команда diff
кажется узким местом в производительности.
Вот строка:
diff -q $dst $new > /dev/null
if ($status) then ...
Может ли быть более быстрый способ сравнения файлов, возможно, пользовательский алгоритм вместо стандартного diff
?
Я полагаю, что cmp
остановится на разнице в первом байте:
cmp --silent $old $new || echo "files are different"
Я как @Алекс Howansky воспользовались 'СМР --молчит' для этого. Но мне нужен как положительный, так и отрицательный ответ, поэтому я использую:
cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'
Затем я могу запустить в терминале или через SSH, чтобы проверить файлы на постоянный файл.
Почему бы вам не получить хэш содержимого обоих файлов?
Попробуйте этот скрипт, назовите его, например, script.sh и запустите его следующим образом: script.sh file1.txt file2.txt
#!/bin/bash
file1=`md5 $1`
file2=`md5 $2`
if [ "$file1" = "$file2" ]
then
echo "Files have the same content"
else
echo "Files have NOT the same content"
fi
Для файлов, которые не отличаются друг от друга, любой метод потребует полного прочтения обоих файлов, даже если чтение было в прошлом.
Альтернативы нет. Поэтому создание хэшей или контрольных сумм в какой-то момент времени требует чтения всего файла. Большие файлы требуют времени.
Поиск метаданных файла намного быстрее, чем чтение большого файла.
Итак, есть ли метаданные файла, которые можно использовать, чтобы установить, что файлы разные? Размер файла или даже результаты команды file, которая считывает только небольшую часть файла?
Пример фрагмента кода с размером файла:
ls -l $1 $2 |
awk 'NR==1{a=$5} NR==2{b=$5}
END{val=(a==b)?0 :1; exit( val) }'
[ $? -eq 0 ] && echo 'same' || echo 'different'
Если размер файлов одинаков, то вы застряли на полном чтении файлов.
Попробуйте также использовать команду cksum:
chk1=`cksum <file1> | awk -F" " '{print $1}'`
chk2=`cksum <file2> | awk -F" " '{print $1}'`
if [ $chk1 -eq $chk2 ]
then
echo "File is identical"
else
echo "File is not identical"
fi
Команда cksum будет выводить количество байт из файла. См. 'человек cksum'.
Потому что я чмо и Дон'т иметь достаточное количество очков репутации, я могу'т добавить этот лакомый кусок в качестве комментария.
Но, если вы собираетесь использовать команду СМР
(и Дон'т нужна/хочу быть многословной) вы можете просто захватить статус выхода. В СМР
Man-странице:
если файл '-' или отсутствует, читается стандартный ввод. Статус выхода равен 0 если входы одинаковые, если разные 1, 2, Если беда.
Таким образом, вы могли бы сделать что-то вроде:
STATUS="$(cmp --silent $FILE1 $FILE2; echo $?)" # "$?" gives exit status for each comparison
if [[$STATUS -ne 0]]; then # if status isn't equal to 0, then execute code
DO A COMMAND ON $FILE1
else
DO SOMETHING ELSE
fi
Делаю некоторые тесты с Raspberry Пи 3Б+ (я'м через оверлей файловой системы, и нужно синхронизировать периодически), я провел сравнение по дифф -м и СС -ы; обратите внимание, что это бревно изнутри на /dev/ГИМ, так что доступ к диску скорости-не проблема:
[[email protected] shm]# dd if=/dev/urandom of=test.file bs=1M count=100 ; time diff -q test.file test.copy && echo diff true || echo diff false ; time cmp -s test.file test.copy && echo cmp true || echo cmp false ; cp -a test.file test.copy ; time diff -q test.file test.copy && echo diff true || echo diff false; time cmp -s test.file test.copy && echo cmp true || echo cmp false
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 6.2564 s, 16.8 MB/s
Files test.file and test.copy differ
real 0m0.008s
user 0m0.008s
sys 0m0.000s
diff false
real 0m0.009s
user 0m0.007s
sys 0m0.001s
cmp false
cp: overwrite âtest.copyâ? y
real 0m0.966s
user 0m0.447s
sys 0m0.518s
diff true
real 0m0.785s
user 0m0.211s
sys 0m0.573s
cmp true
[[email protected] shm]# pico /root/rwbscripts/utils/squish.sh
Я делал это пару раз. СМР -с последовательно были немного короче раз на тестовом ящике, который я использовал. Так что если вы хотите использовать ЦМП -s, чтобы сделать вещи между двумя файлами....
identical (){
echo "$1" and "$2" are the same.
echo This is a function, you can put whatever you want in here.
}
different () {
echo "$1" and "$2" are different.
echo This is a function, you can put whatever you want in here, too.
}
cmp -s "$FILEA" "$FILEB" && identical "$FILEA" "$FILEB" || different "$FILEA" "$FILEB"