© Иван Рощин, Москва
| : bestview@mtu-net.ru | |
| WWW | : http://www.ivr.da.ru |
(«Мир ПК» 11/2006, 6/2007)
Для сравнения содержимого файлов служит команда fc. По умолчанию она выводит результат своей работы на экран: в первой строке сообщение «Сравнение файлов» и далее имена сравниваемых файлов (на экране эта информация может занимать несколько строк, но логически это всё равно одна строка), а во второй строке при совпадении файлов выводится сообщение «FC: различия не найдены» (во всяком случае, именно так оно выглядит у меня в Windows 95 RUS; очевидно, в других версиях ОС текст этого сообщения может быть другим). Если же файлы не совпадают, то во второй и последующих строках выводится информация об обнаруженных различиях.
Таким образом, можно посмотреть, что вывела на экран команда fc, и, исходя
из этого, решить, копировать ли информацию из нового файла в старый. Но мне
хотелось этот процесс полностью автоматизировать, написав
Тут и возникла проблема: обнаружилось, что команда fc не возвращает код
выхода, зависящий от того, совпадают сравниваемые файлы или нет. В обоих
случаях, как я проверил экспериментально, возвращается 0. И как же тогда
проверить результат работы этой команды в
В принципе можно было бы написать собственную программу для сравнения файлов, возвращающую код выхода, который зависит от совпадения сравниваемых файлов. Но хотелось найти более простое решение. И тут я вспомнил об имеющейся у меня программе ssed 3.62.
Ssed
Для меня в данной ситуации было важно то, что в скрипте для ssed может быть использована команда завершения работы с возвращением указанного кода выхода. Исходя из этого, я решил сделать так: направить выход команды fc на вход ssed, а скрипт для ssed составить так, чтобы при совпадении второй строки обрабатываемого текста (который является выходом команды fc) со строкой «FC: различия не найдены» ssed возвращал код выхода 255, а в противном случае обычный код выхода (0, если при работе ssed не было никаких ошибок).
Скрипт получился очень простым:
2 s/^FC: различия не найдены$// T q255
Чтобы объяснить, как он работает, расскажу сначала в двух словах, как вообще ssed обрабатывает текст. В простейшем случае он читает одну строку текста, последовательно выполняет перечисленные в скрипте команды, выдаёт обработанную строку на выход, а затем все эти действия повторяются для следующей строки текста, и так далее, пока текст не кончится.
В первой строке вышеприведённого скрипта находится команда s (поиск и замена подстроки). Двойка перед ней означает, что она будет выполнена только для второй строки обрабатываемого текста.
Подстрока для поиска в этой команде «^FC: различия не найдены$», где <^> обозначает начало строки, а <$> конец (т.е. перед искомой подстрокой и после неё в строке ничего не должно быть). Как видим, это та самая строка, которая выводится командой fc при совпадении файлов (и это именно вторая строка, выводимая командой fc, поэтому и перед командой поиска и замены стоит 2).
Подстрока для замены в этой команде пустая строка (что никакого значения не имеет, так как обработанный текст, полученный в результате работы ssed, в данном случае никак не используется: нам ведь надо только получить код выхода). Команда поиска и замены нужна в этом скрипте, только чтобы потом проверить, было ли совпадение при её выполнении или нет.
Эта проверка как раз производится в следующей строке скрипта (команда T). Если для текущей обрабатываемой строки не было зафиксировано совпадения при выполнении команды поиска и замены (напомню: если обрабатывается не вторая строка текста, то вышеописанная команда поиска и замены не будет выполняться, а значит, совпадения заведомо не будет зафиксировано), то при выполнении команды T обработка текущей строки текста заканчивается и начинается новый цикл (обработка следующей строки текста). Если же совпадение было, то эта команда ничего не делает просто происходит переход к следующей команде.
Команда q255 в третьей строке скрипта это команда завершения работы с возвращением кода выхода 255. Как следует из описания предыдущих команд, эта команда выполняется, только если вторая строка обрабатываемого текста это «FC: различия не найдены». Иначе эта команда не выполнится и выход из ssed произойдёт после просмотра всего поданного ему на вход текста; в этом случае ssed вернёт код 0 (обычный код выхода).
Рассмотренный скрипт может быть записан в одну строку (это позволяет задавать его прямо в командной строке при запуске ssed):
2s/^FC: различия не найдены$//;T;q255
Итак, мне оставалось только написать
@fc %1 %2 | ssed -n "2s/^FC: различия не найдены$//;T;q255" @if not errorlevel 255 copy /y %1 %2 @del %1
Символ @ перед каждой его строкой нужен, чтобы эти строки не печатались при
выполнении
В первой строке вызывается команда fc, которой в качестве входных
параметров передаются имена нового и старого файлов, указанные при запуске
Далее в первой строке идёт символ <|>, обозначающий, что всё
выводимое командой fc будет передано на вход следующей команды. В данном
случае это команда вызова ssed с опцией
Во второй строке анализируется код выхода, возвращённый последней выполненной командой (т.е. командой вызова ssed), и если он меньше 255 (файлы не совпадают), то вызывается команда copy для копирования содержимого нового файла в старый. Опция /y в этой команде отключает выдачу запроса о подтверждении перезаписи файла.
В третьей строке находится команда del, удаляющая новый файл.
Замечу, что рассмотренный
Впоследствии проверку совпадения файлов мне довелось
использовать при решении ещё одной задачи написании
Например, есть некая программа program.exe, при запуске которой в командной строке указываются имена двух файлов; она обрабатывает данные из первого файла и записывает результат во второй. Есть тесты, каждый из которых состоит из файла с данными и файла с результатом правильной обработки этих данных. Допустим, таких тестов два, в первом эти файлы называются test_1.txt и right_1.txt, а во втором соответственно test_2.txt и right_2.txt. Также известно, что при обработке этих тестовых данных программа должна завершать работу с нулевым кодом выхода.
Нужно написать
Вот выполняющий эту задачу
@echo off program.exe source_1.txt result_1.txt if errorlevel 1 goto error1 fc right_1.txt result_1.txt | ssed -n "2s/^FC: различия не найдены$//;T;q255" if not errorlevel 255 goto error1 del result_1.txt program.exe source_2.txt result_2.txt if errorlevel 1 goto error2 fc right_2.txt result_2.txt | ssed -n "2s/^FC: различия не найдены$//;T;q255" if not errorlevel 255 goto error2 del result_2.txt echo Test passed! goto end :error1 echo Error in test 1! goto end :error2 echo Error in test 2! :end
Он выводит сообщение «Test passed!», если тестирование прошло успешно, и «Error in test 1!» или «Error in test 2!», если соответствующий тест не пройден (т.е. тестируемая программа завершилась с ненулевым кодом выхода и/или результат её работы оказался не таким, каким должен быть). Если не пройден первый тест, то второй не обрабатывается.
При прохождении каждого теста создаётся временный файл с результатом работы программы (для первого теста result_1.txt, для второго result_2.txt). Он удаляется, если тест пройден успешно, иначе остаётся, и можно впоследствии сравнить его с правильным результатом для выявления конкретного различия между ними.
Думаю, нетрудно догадаться, как адаптировать этот
За время, прошедшее после написания статьи «Проверка совпадения двух файлов в пакетном режиме» («Мир ПК» №11/06), я обнаружил следующее:
ssed -n "2s/^FC: различия не найдены$//;T;q255"Как я выяснил экспериментальным путём, при выполнении этой команды ОС перекодирует содержащийся в ней скрипт из кодировки DOS (CP866) в
В связи с вышеизложенным представляет интерес нахождение такого способа проверки совпадения двух файлов, который работал бы в обеих вышеуказанных ОС. Могу предложить два способа.
ssed -n -f check_eq.sedТеперь никакого перекодирования скрипта происходить не будет, и он будет работать правильно.
ssed -n "2s/^FC: \xE0\xA0\xA7\xAB\xA8\xE7\xA8\xEF \xAD\xA5 \xAD\xA0\xA9\xA4\xA5\xAD\xEB$//;T;q255"Но, как видите, длина скрипта при этом заметно возрастает. В результате строка
1Фигурнов В.Э. IBM PC
для пользователя.
|
Другие мои статьи о
|