1 (изменено: orchara, 2013-02-11 18:06:58)

Тема: CMD/BAT: поиск в txt файле повторяшихся строк

Доброго времеени суток. Поставленна задача: найти в коталоге повторяюшиеся файлы (тоесть найти файл 1.mp3, копии которого могу лежать в многих папках).
Мой планируемый алгоритм - 1) Создать txt файл в который будут занесены все названия и расширения файлов
                                                 2) Построчно пройтись по созданному файлу и создать новый файл где будут указаны только повторяшиеся файлы с указанием полных путей к ним.

В написание bat файла застопорился на шаге перебора данных в созданном списке файлов. Не знаю как создать алгоритм перебора и отсева правильно.

Заранее спасибо.

PS.
Не иклченно, что я не правильно пошел в плане создания алгоритма. За варианты более простого решения задачи нахождения повторяюшихся файлов огронейшее спасибо.


@echo off
chcp 1251
echo vvedite imya texstovogo faila
:sozdanie
set /p "naz=Vashe nazvanie?"
if not exist %naz%.txt goto notexist
echo fail s takim imenem sushestvuet
set /p "vub=Jelaete vvesti drugoe imya (y/n)?"
if %vub%==y goto sozdanie
if %vub%==n goto exit
:notexist
for /r . %%i in (*.*) do (
echo %%~ni%%~xi >> %naz%.txt
)
for /f %%i In (%naz%.txt) do (
) 
:exit
pause

Чуть позже меня немного осенило как можно реализовать отсев повторяюшихся файлов. Попробую наглядно его описать:
1) Имеем файл с названием файлов (1.txt)
2) Скрипт вырезает первый член списка и вносит его в новый созданный txt файл. (2.txt) Плолучаем 1.txt со старым списком файлов  - первый член. И 2.txt  первым из списка файлом
3) Проверяем все оставшиеся файлы в 1.txt на совпадение с 2.txt. Если такое совпадение происходит, то вырезаем и вствляем в 2.txt. (в итоге все файлы с одинаковым именем окажутся в 2.txt. )
4) Данные о совпавших файлах вырезаем и вставляем в опять же созданный 3.txt.
5) Если совпадений не было, то файл просто стирается из 2.txt
6) Алгоритм проводим по каждому члену списка 1.txt пока он не опустеет.
7) В завершение дабы не захломлять корень файлами, можно скопировать информацию о всех повторяюшихся файлах в 1.txt. А 2ой и 3ий дкументы удалить.

Как реализовать этот алгоритм не представля. Ибо не зна как сдеать вырезание одной строки в ругой txt. И как задать лгоритм перебора со сравнением путем консольных команд.

Заранее спасибо за помошь. (Возможно я перемудрил с алгоритмами)

2

Re: CMD/BAT: поиск в txt файле повторяшихся строк

orchara, пора Вам уже научиться правильно оформлять темы.

Добавьте префикс языка («CMD/BAT: ») в заголовок темы. Оформите код тэгом «code».

3

Re: CMD/BAT: поиск в txt файле повторяшихся строк

А, если дублирующийся файлы есть только в подкаталогах текущего каталога, но в самом текущем (список файлов которого в 1.txt) каталоге нет - то эти файлы уже дублирующимися не считаются?

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

WBR. Roman

4

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rom5, дождёмся реакции автора на замечание.

5

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rom5 пишет:

А, если дублирующийся файлы есть только в подкаталогах текущего каталога, но в самом текущем (список файлов которого в 1.txt) каталоге нет - то эти файлы уже дублирующимися не считаются?

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

Насчет подкаталогов, не понял вопроса... алгоритм поиска собирает перечень всех файлов в дереве каталогов откуда запускается.
В файле 1.txt собран перечень всех файлов каталогов/подкаталогов где лежит bat файл. Но в нем может быть например файл 1.mp3 раза 2-3 (копии одного и того же файла могут хранится в разных папках). Алгоритм и нацелен выбрать все повторения, дабы указать пользователю на все копии.

6

Re: CMD/BAT: поиск в txt файле повторяшихся строк

orchara пишет:

...
Ибо не зна как сдеать вырезание одной строки в ругой txt. И как задать лгоритм перебора со сравнением путем консольных команд.

"Вырезание" строки действительно реализовывать не сильно удобно - надо перезаписывать весь файл с пропуском строки с ранее определенным номером (например, предварительно в цикле наращивать в некой переменной номер текущей строки). Возможно, что можно обойтись и без "вырезания".

Кстати, для поиска дублей "в тексте ниже" - можно попробовать читать содержимое этого же файла еще одним вложенным циклом "FOR /F" с указанием параметра пропуска определенного количества строк с начала файла (skip=n).


Но мне кажется проще попробовать сделать так:
- после создания Вашего 1.txt, в котором у Вас по файлам только имя+расширения, отсортировать его содержимое в другой текстовый файл командой:


sort 1.txt /o 1_sort.txt

таким образом в 1_sort.txt все дублирующиеся имена будут располагать "одним пакетом";

- для избавления от уникальных имен организовать цикл чтения этого 1_sort.txt, в котором запоминать значение текущей строки (для сравнения) и вести накопление количества повторений значений строк (имен файлов), если при смене имени на новое по прежнему значению было подсчитано более одного повтора - значит в прежнем имени были дубли.

Для вывода дублей с полными путем, можно сделать так:
- в самом первом Вашем цикле выводить данные и с указанием пути текущего файла в еще один файл (1p.txt) :


echo.> 1.txt
echo.> 1p.txt
for /r . %%i in (*.*) do (
    echo %%~ni%%~xi >> 1.txt
    echo %%~pi%%~ni%%~xi >> 1p.txt
)

А для вывода по имени файла его дублей с путями воспользоваться командой поиска вхождений этого имени в наш 1p.txt:


find /I "\имя_и_расширение_дублирующегося_файла" 1p.txt >> dub_p.txt
WBR. Roman

7

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Не знаю как создать алгоритм

Всегда рекомендую себя представить на месте машины и мысленно выполнить все действия:


1. получить список файлов
2. начать с начала списка
3. взять имя из списка (А)
4. взять следующее имя (Б)
5. сравнить элементы А и Б
6. сохранить результат
7. если есть следующее имя для Б, то к 4
8. если есть следующее имя для А, то к 3
( 2 * b ) || ! ( 2 * b )

8

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rom5 пишет:

А для вывода по имени файла его дублей с путями воспользоваться командой поиска вхождений этого имени в наш 1p.txt:


find /I "\имя_и_расширение_дублирующегося_файла" 1p.txt >> dub_p.txt

Подумалось, что будет удобнее использовать не "find", а "findstr". В общем стоит глянуть подсказку "findstr /?" и поискать примеры использования регулярных выражений.

WBR. Roman

9

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rom5 пишет:

поискать примеры использования регулярных выражений

В .cmd?

10

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rom5 пишет:

... удобнее использовать не "find", а "findstr"...

Разве автору достаточно сравнить имена файлов? Мне думается, что ему требуется сравнивать именно сами файлы и выводить дубли, если такие имеются. Хотя этот способ не сработает, если есть две одинаковые композиции (ведь сравнение изначально планировалось для mp3 файлов), но с разными тегами, то они распознаются как разные файлы.

( 2 * b ) || ! ( 2 * b )

11

Re: CMD/BAT: поиск в txt файле повторяшихся строк

dir /s /-c 1.mp3 | find /i "1.mp3"

Я конечно далек от мысли... (с)

12 (изменено: UNDYING, 2013-02-16 19:02:54)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Если откинуть первоначальное требование автора - поиск повторяющихся строк в файле, а сразу подступиться к поиску файлов с одинаковыми именами, то решение "в лоб":


@echo off
set SEARCHMASK=*.*
set SEARCHPATH=%CD%
set WORKPATH=%TEMP%\%RANDOM%_%RANDOM%
md %WORKPATH%\dup
md %WORKPATH%\nondup
for /f "tokens=* delims=:" %%A in ('dir /b /s /on /a %SEARCHPATH%\%SEARCHMASK%') do (
echo "%%A" >> %WORKPATH%\%%~nxA
)
for /f "tokens=* delims=:" %%A in ('dir /b /on /a-d %WORKPATH%') do (
(type %WORKPATH%\%%A | findstr /N "." | findstr /b "2:">nul) && (move %WORKPATH%\%%A %WORKPATH%\dup\%%A 2>&1 >nul) || (move %WORKPATH%\%%A %WORKPATH%\nondup\%%A 2>&1 >nul)
)
echo "Files with duplicate names:"
for /f "tokens=* delims=:" %%A in ('dir /b /on /a-d %WORKPATH%\dup') do (
echo %%A
type %WORKPATH%\dup\%%A
)
ping -n 4 127.0.0.1 >nul
rd /s/q %WORKPATH%

Из недостатков - защиты "от дурака" нет, файлы дожны быть, связка из type, двух findstr и move работает крайне (!) медленно. После запуска смело идите пить чай, разговаривать с девушками и заниматься другими не менее полезными и приятными вещами, правда это - уже оффтоп.
PS.
Писалось и проверялось на Win 7 Pro, на XP и 2k конструкция вида:


(type %WORKPATH%\%%A | findstr /N "." | findstr /b "2:">nul) && (move %WORKPATH%\%%A %WORKPATH%\dup\%%A 2>&1 >nul) || (move %WORKPATH%\%%A %WORKPATH%\nondup\%%A 2>&1 >nul)

может работать не так как надо.

13 (изменено: Rumata, 2013-02-17 03:05:54)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Коллега smaharbA показал образчик лаконизма и простоты решения:

dir /s /-c 1.mp3 | find /i "1.mp3"

Фактически, его пример и этот алгоритм решают проблему


@echo off

setlocal enabledelayedexpansion

:: Все найденные файлы сохраняются в файл %allfiles%
set "allfiles=allfiles.txt"

:: Все найденные дубликаты сохраняются в файл %dupfiles%
set "dupfiles=dupfiles.txt"

:: Ведется поиск файлов с расширением mp3
:: во всех подкаталогах текущего каталога
dir /b /s "*.mp3" >"%allfiles%"

set /a count=0

(
for /f "usebackq tokens=*" %%a in ( `
    type "%allfiles%" 
` ) do (
    set /a count+=1
    more +!count! "%allfiles%" | findstr /l /e /c:"\\%%~nxa" && (
        echo %%~a
        echo.
    )
)
)>"%dupfiles%"
( 2 * b ) || ! ( 2 * b )

14

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rumata изящнее, но не без недостатков. Обратите внимание на "выброс" в "dupfiles.txt", сказывается использование more:

+n      Начало вывода первого файла со строки с номером n.

^^ по хелпу ясно, что more покажет строку N и (как минимум!) два десятка следущих, в итоге мы получаем опять борбу с дубликатами, уже в результирующем списке дублей.
Как бороться? Навскидку приходит решение через findstr (вместо more) - в итоге ещё один вложенный цикл и пару findstr в придачу. Работать будет, но "аццки" медленно, главные "тормоза" здесь циклы.
Или, ежели есть простой вариант реализации head, можно оставить с more.

Как бонус - сравнение скорости моего и вашего вариантов(findup и findup_2, соответственно), тестовая директория, 245 файлов, 5 уровней вложенности, 15 "дублей" (Win 7 pro, core 2 e5300):

PS H:\repository\releng\3rdparty> foreach ($n in 'findup.cmd', 'findup_2.cmd' ) {(Measure-Command {cmd.exe /r $n}).TotalMilliseconds}
44798,1988
31492,5062

Хотя из-за "разности" итогового списка - сравнивать не совсем корректно, но лаконизм на лицо, порядка 33-35 %.

15 (изменено: Rumata, 2013-02-17 09:46:54)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

UNDYING, коллега! Я не понял Вашу фразу про "выброс". Я специально проверил на каталоге, в подкаталогах которого заведомо есть одноименные jpg-файлы. Были выбраны только дубликаты (имен файлов, естественно). Повторов не было. Команда more +n выбрана не случайно. Посмотрите еще раз приведенный мной алгоритм.

У меня нелокализованная версия Win Vista

+n      Start displaying the first file at line n

Это тоже самое, только на англ.

Но! При выполнении more +n пропускаются именно n первых строк. А это в корне противоречит справке по команде - "вывод файла со строки n". На самом деле "вывод файла со строки n+1".

На PS не пробовал, так как нет опыта написания скриптов на этом мудреном языке.

( 2 * b ) || ! ( 2 * b )

16

Re: CMD/BAT: поиск в txt файле повторяшихся строк

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

... at line n

должна была бы читаться

... за строкой n

( 2 * b ) || ! ( 2 * b )

17 (изменено: UNDYING, 2013-02-17 11:18:50)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rumata, спасибо за оперативность.

Возможно это не правильная локализация, и часть фразы...

Вы ведёте счёт с единицы?

more +0 file

Выводит c 1-й строки (с точки зрения "программера" - с нулевой), при +1 со второй и т.д. Интересный баг, чуствуются души суровых бородатых мужчин с красными глазами.
more - это pager, который выбрасывает текст "страницей", т.е. "со строки N я выброшу страницу текста 80х25".

Я специально проверил на каталоге, в подкаталогах которого заведомо есть одноименные jpg-файлы. Были выбраны только дубликаты (имен файлов, естественно). Повторов не было. Команда more +n выбрана не случайно

Алгоритм, посмотрю ещё разок, может в скрипте недочёт, заодно попробую выяснить в чём причина и проверю на зоопарке XP, 2k3,2k8.
Для теста попробуйте прогнать пример, если не затруднит:

for /l %%a in (10,1,99) do (md %cd%\%%a
echo.>%cd%\%%a\readme.txt)

И скрипт, соответственно. Каков будет результат?

Я немного подумал, каким образом можно сократить кол-во циклов в скрипте, и в муках родил:

@echo off
set searchmask=*.*
set searchpath=%cd%
set workpath=%temp%\%random%_%random%
md %workpath%\dup
for /f "tokens=* delims=:" %%a in ('dir /b /s /on /a %searchpath%\%searchmask%') do (
if exist %workpath%\%%~nxa (fsutil hardlink create %workpath%\dup\%%~nxa %workpath%\%%~nxa 2>&1 >nul)
echo "%%a" >> %workpath%\%%~nxa)
2>nul type %workpath%\dup\*
rd /s/q %workpath%
exit /b 0

Один цикл, результат исполнения на том же "тазике" с тем же набором файлов ~2 сек.
Недостаток:

Для работы с программой FSUTIL требуются права администратора.

/off PowerShell в примере выше используется только для измерения времени исполнения cmd.exe /c %тестовый_скрип%. И да, он сильно непривычен, в сравнении tcsh/bash/zsh.

18 (изменено: Rumata, 2013-02-17 15:51:32)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Вы ведёте счёт с единицы?

UNDYING. Честно говоря затрудняюсь ответить без примеров. Уж простите за большую порцию оффтопа. Я считаю, что программисты, авторы программ для работы с текстом были мудры, и создали свои программы так, чтобы они правильно считали нумерацию строк текстового файла, начинающуюся с единицы.

Примеры вывода пронумерованных строк исходного файла (unix, cygwin)


seq 11 15 | awk '{ print NR, $0; }'
seq 11 15 | perl -ple '$_ = "$. $_"'
seq 11 15 | sed =

more (unix) - опция +n утверждает "выводить, начиная со строки номер n" (поэтому +0 и +1 эквиваленты)


seq 11 15 | more +0
seq 11 15 | more +1
seq 11 15 | more +2

more (dos) - опция +n утверждает "пропустить n строк" (поэтому +0 выводит с начала файла, +1 пропускает одну строку и печатает, начиная со строки 2. И т.д.)


( for /l %l in ( 11, 1, 15 ) do @echo %l ) | more +0
( for /l %l in ( 11, 1, 15 ) do @echo %l ) | more +1
( for /l %l in ( 11, 1, 15 ) do @echo %l ) | more +2

====

Считаю, что в данном случае рэдмондские волшебники выбрали путь наименьшего сопротивления и считают строки с нуля, что в корне неверно - с нуля можно считать внутренние объекты программы (элемент массива, позиция в строке, позиция в файле и т.д.), но отображаемые объекты (в данном случае строки файла) должны нумероваться натуральными числами.

( 2 * b ) || ! ( 2 * b )

19 (изменено: UNDYING, 2013-02-17 23:02:29)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rumata, благодарю за примеры, но суть не в том:
Если создать тестовый набор циклом

for /l %%a in (10,1,99) do (md %cd%\%%a
echo.>%cd%\%%a\readme.txt)

то вывод скрипта из сообщения


...
B:\94\readme.txt
B:\95\readme.txt
B:\96\readme.txt
B:\97\readme.txt
B:\98\readme.txt
B:\99\readme.txt
B:\93\readme.txt

B:\95\readme.txt
B:\96\readme.txt
B:\97\readme.txt
B:\98\readme.txt
B:\99\readme.txt
B:\94\readme.txt

B:\96\readme.txt
B:\97\readme.txt
B:\98\readme.txt
B:\99\readme.txt
B:\95\readme.txt

B:\97\readme.txt
B:\98\readme.txt
B:\99\readme.txt
B:\96\readme.txt

B:\98\readme.txt
B:\99\readme.txt
B:\97\readme.txt

B:\99\readme.txt
B:\98\readme.txt

а из сообщения


...
"B:\75\readme.txt" 
"B:\76\readme.txt" 
"B:\77\readme.txt" 
"B:\78\readme.txt" 
"B:\79\readme.txt" 
"B:\80\readme.txt" 
"B:\81\readme.txt" 
"B:\82\readme.txt" 
"B:\83\readme.txt" 
"B:\84\readme.txt" 
"B:\85\readme.txt" 
"B:\86\readme.txt" 
"B:\87\readme.txt" 
"B:\88\readme.txt" 
"B:\89\readme.txt" 
"B:\90\readme.txt" 
"B:\91\readme.txt" 
"B:\92\readme.txt" 
"B:\93\readme.txt" 
"B:\94\readme.txt" 
"B:\95\readme.txt" 
"B:\96\readme.txt" 
"B:\97\readme.txt" 
"B:\98\readme.txt" 
"B:\99\readme.txt" 

С нуля или с единицы - суть не в том, а что в примере результат нужно прогонять через конструкцию вида:

cat dupfiles.txt | sort | uniq

Пока пробовал, нашёл ошибку у себя, исправленный вариант:

@echo off
set searchmask=*.*
set searchpath=%cd%
set psfx=%searchpath:~-1%
if %psfx% == \ (set searchpath=%searchpath:~0,-1%)
set psfx=
set workpath=%temp%\%random%_%random%
md %workpath%\dup
for /f "tokens=* delims=:" %%a in ('dir /b /s /on /a %searchpath%\%searchmask%') do (
if exist %workpath%\%%~nxa (fsutil hardlink create %workpath%\dup\%%~nxa %workpath%\%%~nxa 2>&1 >nul)
echo "%%a" >> %workpath%\%%~nxa)
2>nul type %workpath%\dup\*
rd /s/q %workpath%
exit /b 0

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

Посмотрел пристально, head не поможет никаким боком.

20

Re: CMD/BAT: поиск в txt файле повторяшихся строк

С нуля или с единицы - суть не в том, а что в примере есть один "баг" - more smile, точнее особенность его работы. Не в алгоритме, не в идее, а в конкретной реализации.

Не понимаю Вас. Покажите короткий и понятный пример, раскрывающий эту особенность.

Ошибка в моем алгоритме есть. Вернее несовершенство его. Для каждого следующего имени находит дубликаты. Это лишнее. Вот например для списка
10\readme.txt
11\readme.txt
12\readme.txt

на просто вывести этот список. Мой алгоритм пишет
11\readme.txt
12\readme.txt
10\readme.txt

12\readme.txt
11\readme.txt

Это верно, но информация избыточна.

( 2 * b ) || ! ( 2 * b )

21 (изменено: Rumata, 2013-02-18 02:25:10)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Ужасное решение получилось, многословное - пришлось использовать несколько ухищрений из-за отсутствия некоторых возможностей.


@echo off

if "%~1" == ":" goto :%~2

if "%~1" == "" (
    echo.Usage: %~n0 pattern
    goto :EOF
)

setlocal

:: шаблон поиска
set "pattern=%~1"

:: Все найденные файлы (полные пути) сохраняются в файл %allfiles%
set "allfiles=%TEMP%\allfiles.txt"

:: Ведется поиск файлов, заданных шаблоном
:: во всех подкаталогах текущего каталога
dir /b /s "%pattern%" >"%allfiles%"

:: Взять список найденных файлов
:: Получить список имен файлов
:: Отсортировать
:: Найти только дубликаты
:: Применить полученный список к списку всех файлов
< "%allfiles%" call "%~f0" : basename | sort | call "%~f0" : uniq | findstr /l /e /g:/ "%allfiles%"

endlocal
goto :EOF


:: Подпрограмма выбирает только имя файла (с расширением)
:: Аналог unix-команд: xargs -IX basename "X"
:basename
for /f "usebackq tokens=*" %%a in ( `
    find /v ""
` ) do @(
    echo.%%~nxa
)
goto :EOF


:: Подпрограмма ищет дубликаты и отображает их
:: Аналог unix-команды: uniq -d
:uniq
setlocal enabledelayedexpansion

set A=
set /a N=0

for /f "usebackq tokens=*" %%a in ( `
    find /v ""
` ) do @(
    if "%%~a" == "!A!" (
        set /a N+=1
        if !N! equ 2 (
            echo.%%~a
        )
    ) else (
        set "A=%%~a"
        set /a N=1
    )
)

endlocal
goto :EOF

Аналогичный код в Unix без использования временного файла:


pattern='*.mp3'
find . -name "$pattern" | grep -f <(find . -name "$pattern" | xargs -IX basename "X" | sort | uniq -d)

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

( 2 * b ) || ! ( 2 * b )

22 (изменено: UNDYING, 2013-02-18 10:25:54)

Re: CMD/BAT: поиск в txt файле повторяшихся строк

Rumata пишет:

Не понимаю Вас. Покажите короткий и понятный пример, раскрывающий эту особенность.

Поправил - сам ошибался (в дискуссиях рождается правда).

Это верно, но информация избыточна.

Да, согласен. Но представим ситуацию в идеале:


for /f %%a in ('наш_скрипт.cmd C:\Music\*.mp3') do (ren "%%a" "%%~dpa%time%%%~xa")
for /f %%a in ('dir /b/s/a-d/on *.mp3') do (copy "%%a" "%cd%\%%~nxa")

a. ищем дубликаты (для mp3, напимер) и при наличии оных, переименовываем (например, в соотвествии с датой создания или содержимым).
b. копируем все файлы (mp3) (например, на флешку)
на пункте a "спотыкаемся" из-за избыточного вывода.


Ужасное решение получилось, многословное - пришлось использовать несколько ухищрений из-за отсутствия некоторых возможностей.

Очень круто, только косметические изменения, и оно некорректно обрабатывает файлы с "!" в имени:

...
< "%allfiles%" call "%~f0" : basename | sort | call "%~f0" : uniq | findstr /l /e /i /g:/ "%allfiles%"
...
:: Ведется поиск файлов, заданных шаблоном
:: во всех подкаталогах текущего каталога
dir /b/s/a-d "%pattern%" >"%allfiles%"
:: ^^ иначе ищем и директории

...

:: Подпрограмма выбирает только имя файла (с расширением)
:: Аналог unix-команд: xargs -IX basename "X"
:basename
for /f "usebackq tokens=*" %%a in ( `
    find /v ""
` ) do @(
    echo.\%%~nxa
)
:: ^^ иначе 123.txt и 1123.txt расцениваются как равнозначные.
:: Но в любом (!) случае "съедаются" восклицательные знаки в именах.

...

:: Подпрограмма ищет дубликаты и отображает их
:: Аналог unix-команды: uniq -d
:uniq
setlocal enabledelayedexpansion

set A=
set /a N=0

for /f "usebackq tokens=*" %%a in ( `
    find /v ""
` ) do @(
    if /I "%%~a" == "!A!" (
        rem ^^ независимо от регистра
        set /a N+=1
        if !N! equ 2 (
            echo.%%~a
        )
    ) else (
        set "A=%%~a"
        set /a N=1
    )
)
...

uniq требует ещё доработки - бывает, "спотыкается" (ищу закономерности) на строках вида:

X:\REPORT.HTML\BACKUP\2011_03_03_13_35_21_250.HTM

Работает очень быстро, хороший код.

Если в ущерб скорости(работает очень медленно), но без создания файлов, то:

@echo off
setlocal enabledelayedexpansion
if "%*" == "" (set mask="*.*") else (set mask="%~1")
(for /f "usebackq tokens=*" %%a in (`
    dir /a-d /b /s %mask%
`) do (
       (dir /a-d /b /s %mask% | find /i /v "%%~a") | (
       (findstr /l /e /c:"\\%%~nxa" 2>&1 1>nul
       ) &&echo.%%~a)))
exit /b 0 & endlocal

Недостаток тот же.

Через создание кучи временных файлов:

@echo off
if "%*" == "" (set mask="*.*") else (set mask="%~1")
set wpath=%temp%\%random%_%random%
md %wpath%\dup
for /f "tokens=* delims=:" %%a in ('dir /b/s/a-d %mask%') do (
    if exist "%wpath%\%%~nxa" (if not exist "%wpath%\dup\%%~nxa" (
        fsutil hardlink create "%wpath%\dup\%%~nxa" "%wpath%\%%~nxa" 2>&1 >nul
    ))
    echo %%a>>"%wpath%\%%~nxa"
)
2>nul type %wpath%\dup\*
2>&1 >nul rd /s/q %wpath%
exit /b 0

Работает шустро и "поддерживает" "!" в именах файлов.
По идее, "спотыкнётся" на символах "%","&" в именах, надо проверить, и для работы требует прав администратора.

23

Re: CMD/BAT: поиск в txt файле повторяшихся строк

UNDYING, спасибо за корректные замечания. О некоторых знал, но не учел, о большинстве других не додумал.

( 2 * b ) || ! ( 2 * b )