Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Определение и работа с некорректными именами файлов (http://forum.oszone.net/showthread.php?t=350070)

ChimMAG 17-11-2021 15:25 2972264

Определение и работа с некорректными именами файлов
 
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 2972268

Цитата:

Цитата ChimMAG
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 2972272

Цитата:

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

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

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

Iska 17-11-2021 17:40 2972273

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

wasp14 17-11-2021 17:46 2972276

Код:

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 2972332

Цитата:

Цитата wasp14
у мя выводит вроде »

Ещё раз - внутри цикла for всё выводит. Но если я через call начинаю работать с переменными ВНЕ цикла, то всё обрезается. Попробуйте такую конструкцию:
Код:

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

:Obrab
echo %X%
exit /b

Цитата:

Цитата Iska
ChimMAG, лучше вообще не использовать языки подобные CMD и PowerShell, если есть сложная обработка имён. »

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

DJ Mogarych 18-11-2021 09:54 2972347

В Powershell есть параметр -LiteralPath, помогает в таких случаях.

megaloman 18-11-2021 10:28 2972360

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 2972402

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 2972412

Цитата:

Цитата megaloman
Поэтому, если аккуратно, то вот так разными способами и ничего не обрезается и не ломается. »

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

Iska 18-11-2021 19:02 2972435

Цитата:

Цитата ChimMAG
Отработал за несколько часов более 300 тыс файлов (по моим прикидкам по тому, что он пробегал; я думал, что гораздо медленнее будет, в реальности скорее всего за 500тыс успел) и отрубился. »

Это как-то совсем несерьёзно. WSH/PoSH, а лучше какой-нибудь чистый C.

Fors1k 18-11-2021 23:35 2972465

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

Iska 19-11-2021 23:14 2972550

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

megaloman 20-11-2021 00:25 2972560

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

Fors1k 20-11-2021 01:41 2972572

Iska, я, так сказать, частично не про пош говорил :wink:


Время: 12:21.

Время: 12:21.
© OSzone.net 2001-