PDA

Показать полную графическую версию : Сравнение строк текстовых файлов, найти разницу.


Alexlook
07-11-2021, 16:55
Всем привет. Нужна помощь.
Есть 2 текстовых файла, внутри каждого построчно списки файлов, 1 строка - 1 название файла. Задача найти файлы которые есть в первом файле и нет во втором и наоборот.

Вот файлы:
______________________________________________
files.txt
_________
test2.bat
test3.bat
LR.bat
LR1(‘а*ў*Ґ*ЁҐ f Ё f1 ў compare).bat
files_07.2021.txt
files_08.2021.txt
’‡ ‹ђ Ћ‘.txt
files.txt
files2.txt
files_10.2021.txt
dif.txt
test.bat
lists.txt
null
date.txt
0411.bat

________________
files2.txt
_______________
LR.bat
LR1(‘а*ў*Ґ*ЁҐ f Ё f1 ў compare).bat
files_07.2021.txt
files_08.2021.txt
’‡ ‹ђ Ћ‘.txt
files_10.2021.txt
dif.txt
test.bat
lists.txt
null
date.txt
0411.bat
0511.bat
Ђ«Ј®аЁв¬.txt
______________________________________



Пока написал вот такой код: он записывает имена файлов из файлов построчно в массивы и сравнивает, выводит если есть совпадение. Тут массивы дублируются псевдомассивами в каждой обработке файлов, это конечно можно убрать. Просто пытаюсь хоть как-то это победить. План был при совпадении строк заменять их например на 0. Затем перебрать массивы и вывести все значения что не 0 в одном списке и во втором.


@echo off
Setlocal EnableDelayedExpansion EnableExtensions
chcp 866
set /a k=0
set /a l=0
set /a j=0
set /a i=0

rem получаю массив строк файла files2.txt
for /f "usebackq delims=" %%a in ("files2.txt") do (
set /a k+=1
set "m!k!=%%a"
set myar[%%j]=%%a
rem echo !myar[%%j]!
)

rem получаю массиы строк файла files.txt при это каждую строку сравниваю с каждой из предыдущего если совпадение меняю на 0
for /f "usebackq delims=" %%b in ("files.txt") do (
set /a l+=1
set "n!l!=%%b"
set myar2[%%i]=%%b
if !myar[%%j]! == !myar2[%%i]! do (
echo !myar[%%j]!
set myar2[%%i]=0
echo !myar2[%%i]! >> myar.txt
)
rem echo !myar2[%%i]!
echo !$l%!

)
rem echo !myar2[%%i]!
rem echo !myar[%%j]!
)
set /a df=12
echo %n12%
echo %m12%





Я нихрена не понимаю:

1. Почему я потом не могу циклом for /l перебрать массивы?
2. Как вывести элемент массива вне цикла не по конкретному индексу, а указывая индекс переменной. В цикле выводится а вне цикла нет.
3. Внутри цикла set myar2[%%i]=0 не меняет значения элемента. Как сделать чтоб менял?
4. Почему где-то операция в кавычках, где -то %%, где-то !!. Я конечно сам это написал но путем копипаста экспериментов и изучения кучи всяких документаций. Но по этому синтаксису внутри цикла так и не нашел ничего внятного. Если кто скажет где почитать буду признателен.
5. Если выводить переменную k или l внутри цикла она не меняет значения, только по окончании, как это работает? Где почитать?
6. Должен ли внутри цикла работать GOTO?

Если кто-то сможет с этим разобраться, возможно есть более простой способ, буду очень благодарен.

YuS_2
07-11-2021, 18:56
возможно есть более простой способ »
есть, но не в cmd, а в powershell:
diff (gc files1.txt) (gc files2.txt)
результат:
InputObject SideIndicator
----------- -------------
0511.bat =>
Алгоритм.txt =>
test2.bat <=
test3.bat <=
files.txt <=
files2.txt <=

megaloman
07-11-2021, 19:44
@Echo Off
cls
Set "File1=Z:\Box_In\files-1.txt"
Set "File2=Z:\Box_In\files-2.txt"

Echo ------- В файле "%File1%" есть а В файле "%File2%" нет
FindStr /I /L /G:"%File2%" /V "%File1%"

Echo ------- В файле "%File2%" есть а В файле "%File1%" нет
FindStr /I /L /G:"%File1%" /V "%File2%"
pause
Exit /B
test1.bat
test2.bat
test21.bat
test22.bat
test31.bat
test32.bat
test3.bat
test2.bat
test23.bat
test22.bat
test33.bat
test32.bat
------- В файле "Z:\Box_In\files-1.txt" есть а В файле "Z:\Box_In\files-2.txt" нет
test1.bat
test21.bat
test31.bat
------- В файле "Z:\Box_In\files-2.txt" есть а В файле "Z:\Box_In\files-1.txt" нет
test3.bat
test23.bat
test33.bat
Если файлы с именами в кодировке 1251 то после cls добавить строку >nul chcp 1251и сохранить батник в 1251 кодировке.

Iska
07-11-2021, 22:11
Alexlook, глобальная цель какова? Тупо WinMerge не устроит?
https://i.imgur.com/cj2Rbwl.png

Elven
08-11-2021, 08:52
1. Почему я потом не могу циклом for /l перебрать массивы?
2. Как вывести элемент массива вне цикла не по конкретному индексу, а указывая индекс переменной. В цикле выводится а вне цикла нет.
3. Внутри цикла set myar2[%%i]=0 не меняет значения элемента. Как сделать чтоб менял?
4. Почему где-то операция в кавычках, где -то %%, где-то !!. Я конечно сам это написал но путем копипаста экспериментов и изучения кучи всяких документаций. Но по этому синтаксису внутри цикла так и не нашел ничего внятного. Если кто скажет где почитать буду признателен.
5. Если выводить переменную k или l внутри цикла она не меняет значения, только по окончании, как это работает? Где почитать?
6. Должен ли внутри цикла работать GOTO? »

1. Потому что cmd не умеет нормально в массивы, он не хранит их сам по себе, разве что спихнуть в файл и из него прочитать. Или создать пачку переменных, и в каждую записать свое значение - получится такой как бы фальшивый массив.
2. Именно так как описано в вопросе - никак, см. п.1
3. Чтобы меняло значение, нужно использовать не %% а !!. Читать в расширенную обработку команд -> тык (https://ab57.ru/cmdlist/setlocal.html)
4, 5. Все та же ссылка, что и в п.3
6. Должен, но использовать его не нужно. Цикл подразумевает под собой обработку некоторого количества значений до выполнения некоторого условия, в то время как GOTO совершает безусловный переход. Это не есть правильно. Кроме того - добавляет головной боли при отладке.

Что же касается создания результирующего файла мне больше нравится Compare-Object (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/compare-object?view=powershell-7.1), да и для обработки массивов лучше гонять powershell. Сказать обо что-нибудь подробнее можно будет только после озвучивания окончательной цели, а то может тут большая часть телодрыжества бесполезна...

Alexlook
08-11-2021, 09:31
YuS_2, Цитировать »

Спасибо, согласен в Power Shell более очевидно как это сделать. Но все же думал сделать в CMD.

Цитировать »

Вот это, похоже то что нужно, я findstr и fc день крутил, но видимо не до конца.
Все думал столько команд неужели нужно изобретать что-то для такой задачи.

Спасибо большое, на выходных думаю доделаю!

Цитировать »

Глобальная цель КР по ОС:

Разработать командный файл, который формировал бы ежемесячный
отчет об изменениях в рабочем каталоге (файлы созданные, удаленные).
Необходимо хранить список файлов в файле истории.

WinMerge кажется не подойдет. Спасибо.

Цитировать »

Спасибо за ответы и ссылки, буду разбираться.

DJ Mogarych
08-11-2021, 10:18
формировал бы ежемесячный
отчет об изменениях в рабочем каталоге (файлы созданные, удаленные).
Необходимо хранить список файлов в файле истории. »
Для этого уже давно придуман файловый аудит, события которого потом легко разбираются тем же Пауэршеллом.

megaloman
08-11-2021, 10:57
Alexlook, Почему ...Не умеете :) Если нельзя но очень хочется, то можно (осторожно)@Echo Off
cls
Call :TxtToMass "Z:\Box_In\Файл первый.txt" "@@A" "NA" 10000

Set "@@A"
Echo NA=%NA%
Echo @@A10005=%@@A10005%
Echo.

Call :TxtToMass "Z:\Box_In\Файл второй.txt" "@@B" "NB" 10000

Set "@@B"
Echo NB=%NB%
Echo @@B10003=%@@A10003%
Echo.

For /L %%i In (10001,1,%NA%) Do Call Echo %%i %%@@A%%i%%
Echo.

For /F "usebackq tokens=1* delims==" %%i In (`Set "@@A"`) Do Echo %%i %%j
Echo.

pause
Exit /B

:TxtToMass
Set /A %~3=%~4
For /F "usebackq delims=" %%i In (`2^>nul More %1`) Do (
Call Set /A %~3+=1
Call Set "%~2%%%~3%%=%%i"
)
Exit /B
создать пачку переменных, и в каждую записать свое значение - получится такой как бы фальшивый массив. »В моём примере так и реализовано. Только для того, чтобы при сортировке элементов массива по имени не нарушался порядок строк из текстового файла я нумерую элементы псевдомассива не 1, 2, 3 а, например, 10001, 10002, 10003. Если делать не так, то при текстовой сортировке имён получим что A100 будет отображаться раньше A2.
Я стараюсь избегать применения Setlocal EnableDelayedExpansion так как применение ! в текстовых литералах при этом приведёт к ошибке. Для Вашего случая, в имени файлов при таком SetLocal не должно быть "!".
Но вообще-то работать с текстами в CMD - надо очень осторожно, есть много служебных символов в CMD, которые, если встретятся в литерале, сломают любую вашу логику.
В примере я применил процедуру (кто-то меня поправит - псевдопроцедуру)
Для облегчения понимания её работы вот кусок для одного массива (псевдомассива, чтобы никого не раздражать) без процедуры.@Echo Off
cls
Set /A NA=10000
For /F "usebackq delims=" %%i In (`2^>nul More "Z:\Box_In\Файл первый.txt"`) Do (
Call Set /A NA+=1
Call Set "@@A%%NA%%=%%i"
)

Set "@@A"
Echo NA=%NA%
Echo @@A10005=%@@A10005%
Echo.

For /L %%i In (10001,1,%NA%) Do Call Echo %%i %%@@A%%i%%
Echo.

For /F "usebackq tokens=1* delims==" %%i In (`Set "@@A"`) Do Echo %%i %%j
Echo.
pause
Exit /B
Процедура удобнее, особенно если одно и то же надо проделать в нескольких местах.
Если GoTo ссылается на метку внутри цикла, у меня не получается. Я использую GoTo внутри цикла на метку вне цикла, чтобы выйти из цикла.
Лучше использовать If@Echo Off
cls
For /L %%i In (1,1,10) Do (
If %%i LEQ 5 (
Echo %%i меньше или равно 5
) Else (
Echo %%i больше 5
)
)
pause
Exit /B

Sham
08-11-2021, 11:01
Нету там никаких массивов. Квадратные скобки - часть имени переменной.

Iska
09-11-2021, 00:47
Глобальная цель КР по ОС:
Разработать командный файл, который формировал бы ежемесячный
отчет об изменениях в рабочем каталоге (файлы созданные, удаленные).
Необходимо хранить список файлов в файле истории. »
Используйте код коллеги megaloman из сообщения №3 (http://forum.oszone.net/post-2971124.html#post2971124).




© OSzone.net 2001-2012