PDA

Показать полную графическую версию : Определение и работа с некорректными именами файлов


ChimMAG
17-11-2021, 15:25
CMD очень не любит имена файлов со всякими !, скобками и прочими символами. Но если попадаются такие - хотелось бы их если не обрабатывать, то хотя бы сообщать скрипту об этом. По конкретике:
for /R %%a in (.) do (set TKatD="%%a"&if "%%a"==!TKatD! (call :ObrabKat))
exit /b

:ObrabKat
echo %TKatD%
set TKat=%TKatD%
exit /b


Что имеем в трассировке:
C:\Users\1\Temp\MS-DOS_Flash>(set TKatD="C:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\." & if "C:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\." == !TKatD! (call :ObrabKat ) )

C:\Users\1\Temp\MS-DOS_Flash>echo "C:\Users\1\Temp\MS-DOS_Flash\\."
"C:\Users\1\Temp\MS-DOS_Flash\\."

C:\Users\1\Temp\MS-DOS_Flash>set TKat="C:\Users\1\Temp\MS-DOS_Flash\\."


Поясняю: команда FOR нормально обрабатывает косячное имя файла, переменная %%a имеет именно это имя. Более того, так как корректно обрабатывается условный переход, то и !TKatD! тоже равен %%a (собственно этот условный переход и был на такой случай расчитан). Но после того, как переходим и просто сразу выводим значение %TKatD% - в нём обрезаются !!! и всё, что между ними. Почему так или как-то можно отследить это?

Далее мне надо войти в данный каталог и уже в нём прошустрить файлы. И, само собой, команда cd %TKatD% не обрабатывается корректно. Тут попытался выйти из положения втавив туда, где имя каталога ещё полное - (cd %%a) - трассировка пишет, что подставляется в строку вроде то, но нет, не срабатывает такой фокус, не заходит.

P.S. Уже на моменте написания я нашёл частичное решение - сравнение нашей переменной и текущего каталога if not %TKat%=="%CD%\" (exit /b) - в этом случае хотя бы пропускается косячные. Но всё равно общий вопрос - почему так происходит остаётся открытым.

megaloman
17-11-2021, 16:24
CMD очень не любит имена файлов со всякими !, скобками и прочими символами. Почему так или как-то можно отследить это? »Надо правильно их употреблять. Потому что Вы используете EnableDelayedExpansion, что предполагает наличие переменных в !!. Соответственно, при обработке строк то, что встречается в !! интерпретируется как переменная с непредсказуемыми последствиями. Выкручивайтесь как-нибудь без EnableDelayedExpansion - уверяю, это возможно. Изложите, чего Вы домогаетесь, можно тогда советовать конкретнее: по обрывкам кода без четкой постановки трудновато, конструкция
(set TKatD="%%a"&if "%%a"==!TKatD! (call :ObrabKat))
меня угнетает, я её не понимаю. Как возможный приём (не решение, только как пример):@Echo Off
cls
Set "TKatD=!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!"
For /R %%d In (.) Do Echo %%d |>nul 2>&1 FindStr /I "\%TKatD%\" &&Call :ObrabKat "%%d"
Pause
Exit /B

:ObrabKat
Echo %1
Dir %1 /s /b /A:-D
Exit /B@Echo Off
cls
For /R %%d In (.) Do (
Set "TKatD=%%d"
Call Echo "%%TKatD%%"
Call :ObrabKat "%%d" "%%TKatD%%"
)
Pause
Exit /B

:ObrabKat
If %1==%2 Echo Ура! %1 %2
Exit /B
Помимо этого, если в имени файла встречается символ не из 866 кодовой страницы, иногда помогает при этом chcp 1251. Надо конкретика задачи.

ChimMAG
17-11-2021, 17:21
конструкция
(set TKatD="%%a"&if "%%a"==!TKatD! (call :ObrabKat))
меня угнетает, я её не понимаю. Как возможный приём (не решение, только как пример): »

Я увидел, что в случае такого странного каталога переменная TKatD далее урезана, а в переменной %%a - полное имя и логика была такая, что, возможно, при присваивании переменная "ломается" и это должно было отсечь такие случаи и не обрабатывать дальше такой каталог. Но это не работает, этот if я убираю, оставляю только call.

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

Iska
17-11-2021, 17:40
ChimMAG, лучше вообще не использовать языки подобные CMD и PowerShell, если есть сложная обработка имён.

wasp14
17-11-2021, 17:46
Echo on

cd /d "%~dp0"

for /F %%a in ('dir /b /s') do ( ...........делай что хочешь с каталогом....... )

exit /b



не, фигня...
можно так(только в цикле учитывать что появится доп."слэш" в конце и убирать его):

@echo on
chcp 65001
for /r %%a in (\) do ( echo %%a )
pause
exit

у мя выводит вроде ↓

for /R %a in (\) do (echo %a )

(echo C:\Activators\\ )
C:\Activators\\

(echo C:\Activators\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\\ )
C:\Activators\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\\

(echo C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\\ )
C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\\

(echo C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\readme\\ )
C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\readme\\

(echo C:\Activators\kmsauto-office\\ )
C:\Activators\kmsauto-office\\

ChimMAG
18-11-2021, 04:56
у мя выводит вроде »
Ещё раз - внутри цикла for всё выводит. Но если я через call начинаю работать с переменными ВНЕ цикла, то всё обрезается. Попробуйте такую конструкцию:
for /R %a in (\) do (set X=%%a&call :Obrab )
exit /b

:Obrab
echo %X%
exit /b

ChimMAG, лучше вообще не использовать языки подобные CMD и PowerShell, если есть сложная обработка имён. »
Так-то согласен... Но сложной обработки имён нет, есть несознательные граждане, которые обзывают файлы как бог на душу придётся (я не про приведённый пример, это просто в тестовом каталоге встретилось), из-за чего скрипты ломаются при любой операции... :-(

DJ Mogarych
18-11-2021, 09:54
В Powershell есть параметр -LiteralPath, помогает в таких случаях.

megaloman
18-11-2021, 10:28
ChimMAG, В вашем примере переменная %X% внутри цикла, хоть Вы ее хотите использовать в процедуре. Поэтому, если аккуратно, то вот так разными способами и ничего не обрезается и не ломается.@Echo Off
cls
Set "BoxIn=Z:\Users"
For /R "%BoxIn%" %%a In (.) Do (
Echo =====
Echo 00000 %%a

Set "X=%%a"
Call Echo 11111 %%X%%

Call :Obrab "%%a" "%%X%%"
Call Set "Y=%%X%%"
Call Echo 66666 %%Y%%
)
Pause
Exit /B

:Obrab
Echo 33333 %~1
Echo 44444 %~2
Call Echo 55555 %%X%%
Exit /B
=====
00000 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
11111 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
33333 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
44444 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
55555 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
66666 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Soft_Out\.
=====
00000 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.
11111 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.
33333 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.
44444 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.
55555 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.
66666 Z:\Users\1\Temp\MS-DOS_Flash\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\Я-Архив\.

wasp14
18-11-2021, 14:42
ChimMAG, ну вот же


C:\Activators
----------------------------------------------------
=>chcp 65001
Active code page: 65001


C:\Activators
----------------------------------------------------
=>for /R %a in (\) do (set X=%a && call :Obrab )


C:\Activators
----------------------------------------------------
=>(set X=C:\Activators\\ && call :Obrab )


C:\Activators
----------------------------------------------------
=>echo Моя переменная для работы: C:\Activators\\
Моя переменная для работы: C:\Activators\\


C:\Activators
----------------------------------------------------
=>exit /b


C:\Activators
----------------------------------------------------
=>(set X=C:\Activators\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\\ && call :Obrab )


C:\Activators
----------------------------------------------------
=>echo Моя переменная для работы: C:\Activators\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\\
Моя переменная для работы: C:\Activators\!!!MS-DOS-ver.5-7 (ms-dos.biz)!!!\\


C:\Activators
----------------------------------------------------
=>exit /b


C:\Activators
----------------------------------------------------
=>(set X=C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\\ && call :Obrab )


C:\Activators
----------------------------------------------------
=>echo Моя переменная для работы: C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\\
Моя переменная для работы: C:\Activators\KMSAuto Net 2015 v1.4.2 Portable\\


C:\Activators
----------------------------------------------------
=>exit /b




Полностью скрипт:


@echo on
chcp 65001

for /R %%a in (\) do ( set X=%%a&&call :Obrab )
pause
exit


:Obrab
echo Моя переменная для работы: %X%
exit /b

ChimMAG
18-11-2021, 16:05
Поэтому, если аккуратно, то вот так разными способами и ничего не обрезается и не ломается. »
Это интересный пример, я попробую использовать его.
Вообще скрипт пробегает по всему дереву, начиная с каталога запуска и считает полную длину файлов вместе с путём и выявляет имена с более 255 символами - с такими файлами бывают проблемы. Я подправил, запустил. Отработал за несколько часов более 300 тыс файлов (по моим прикидкам по тому, что он пробегал; я думал, что гораздо медленнее будет, в реальности скорее всего за 500тыс успел) и отрубился. Добавил вывод в отдельный файл трассировку пробегаемых каталогов и счётчик просмотренного. Посмотрю что из этого получится :-)

Iska
18-11-2021, 19:02
Отработал за несколько часов более 300 тыс файлов (по моим прикидкам по тому, что он пробегал; я думал, что гораздо медленнее будет, в реальности скорее всего за 500тыс успел) и отрубился. »
Это как-то совсем несерьёзно. WSH/PoSH, а лучше какой-нибудь чистый C.

Fors1k
18-11-2021, 23:35
Iska, ну что вы) Posh еще не до конца изучен. Как-то слишком быстро работают на нем скрипты.
Даже если posh помог вам решить задачу, при следующей потребности опять придется писать скрипт.
А еще, вон, у меня друг есть, который до сих пор ни разу не пользовался пошем, и нормально же живет.

Iska
19-11-2021, 23:14
Fors1k, я имею в виду, что «голые» native командлеты, даже с учётом прокладки в виде .Net Framework, могут исполняться достаточно быстро. Но как только дело доходит до: обработки строк, выделения памяти, сборки мусора, не говоря уже про циклы и т.п. — PoSH становится весьма нетороплив, как и любой другой интерпретируемый язык. Чистый C с ассемблерными вставками в критических местах остаётся самым шустрым вариантом (из приемлемых по скорости программирования) для написания «фильтров» (что-то подали на вход — что-то получили на выходе).

megaloman
20-11-2021, 00:25
ChimMAG, Когда-то вычитал заповедь: не перепрограммируй функцию квадратного корня. Неужели нельзя найти что-то профессиональное готовое для сбора какой-то статистики?

Fors1k
20-11-2021, 01:41
Iska, я, так сказать, частично не про пош говорил :wink:




© OSzone.net 2001-2012