Форум программистов, компьютерный форум, киберфорум
Batch (CMD/BAT)
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.83/65: Рейтинг темы: голосов - 65, средняя оценка - 4.83
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
1

for /f "delims=" %%b in ('dir !DirName! /b /s /a-d') do () жрёт символы "!" и "^"

31.10.2013, 22:01. Показов 12312. Ответов 27
Метки нет (Все метки)

Добрый день, коллеги.

День сегодня убил, но так и не понял что делать, может поможете добрым советом.

Кусок батничка:
Код
@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion

SET DirName=!CD!
IF EXIST 1.txt DEL 1.txt

  FOR /F "DELIMS=" %%B IN ('DIR !DirName! /B /S /A-D') DO (
    ECHO %%B>>1.txt
  )
Понятно, что сканируем дерево каталогов от текущего и до дна, имена всех попавшихся по дороге файлов складываем в 1.txt.

Всё хорошо и просто, но. Если путь к файлу содержит символы "!"или "^", то они теряются.

От "SETLOCAL EnableExtensions EnableDelayedExpansion" отказаться не могу, у меня внутри цикла FOR есть ещё и счётчик. Поэтому и гимор с "!".

Что делать?
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.10.2013, 22:01
Ответы с готовыми решениями:

Почему в начале вывода команды DIR указываются две папки с именами "." и "..", хотя их нигде нет?
Привет. Почему в выдаче в начале первые две папки имеют имена "." и "..", хотя их нигде нет?

Избавиться от сообщений "Файл не найден", "Системе не удается найти указанный путь", "Устройство не готово"
Здравствуйте. В батнике присутствует поиск файлов: for %%i in (c d e f g h i j k l m n o p q r s t...

Цикл for /f "usebackq delims=" и модификаторы короткого имени файла 8.3
Добрый день! Столкнулся с багом\фичей при использовании цикла for. Задача стояла такая -...

Искать в файле из директории "base" строки, которые содержат строку из "list.ini" и отсеивать их
Здравствуйте. Имеется данный Batch: @ECHO off SETLOCAL EnableExtensions EnableDelayedExpansion ...

27
1771 / 753 / 130
Регистрация: 09.04.2011
Сообщений: 1,325
31.10.2013, 22:44 2
E30M20B20, а если так?
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ECHO OFF
SETLOCAL EnableDelayedExpansion
 
SET DirName=^^!2^^!
echo !DirName!
pause
::IF EXIST 1.txt DEL 1.txt
 
  FOR /F "DELIMS=" %%B IN ('DIR /B /S /A-D "!DirName!"') DO (
endlocal
    ECHO %%B
  )
pause
exit /b
Миниатюры
for /f "delims=" %%b in ('dir !DirName! /b /s /a-d') do () жрёт символы "!" и "^"  
1
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
31.10.2013, 23:16  [ТС] 3
Так символы не ест, но не работает счётчик. Мой батник чуть подробнее:

Код
@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion

SET DirName=!CD!
SET /A N=0
IF EXIST 1.txt DEL 1.txt

  FOR /F "DELIMS=" %%B IN ('DIR !DirName! /B /S /A-D') DO (
    SET /A N+=1
    IF /I "!N!"=="1" (ECHO MPCPLAYLIST>1.txt)
    ECHO !N!,type,^0>>1.txt
    ECHO !N!,filename,%%B>>1.txt
  )
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
31.10.2013, 23:45 4
Вынести вывод в отдельную процедуру, в которой будет setlocal disabledelayedexpansion, а в конце endlocal

Добавлено через 1 минуту
Хотя нет, вынести не получится, придется прямо в цикле
Bash
1
2
3
setlocal disabledelayedexpansion
echo %%B
endlocal
0
1771 / 753 / 130
Регистрация: 09.04.2011
Сообщений: 1,325
31.10.2013, 23:46 5

Не по теме:

E30M20B20, наверное не стоит искусственно создавать сложности для батников, используя в именах директорий и файлов спецсимволы. Постарайтесь от их избавиться вручную. Если вам нужно "поднять" директории вверх, попробуйте использовать например нижний подчерк "_folder1 "


поясните строчку 11 кода
Bash
1
ECHO !N!,type,^0>>1.txt
0
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 00:06  [ТС] 6
sov44, это такой формат плейлиста от MediaPlayerClassic

Код
MPCPLAYLIST
1,type,0
1,filename,D:\3\01. Paul Mauriat - El Bimbo.mp3
2,type,0
2,filename,D:\3\04-Neghivaya_voda.alac
Добавлено через 12 минут
FraidZZ, Но как вытащить наружу счётчик?

Код
@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion

SET DirName=!CD!
SET /A N=0
IF EXIST 1.txt DEL 1.txt

  FOR /F "DELIMS=" %%B IN ('DIR !DirName! /B /S /A-D') DO (
    SET /A N+=1
    IF /I "!N!"=="1" (ECHO MPCPLAYLIST>1.txt)
    ECHO !N!,type,^0>>1.txt
setlocal disabledelayedexpansion
    ECHO !N!,filename,%%B>>1.txt
endlocal
  )
sov44, это большая фонотека (больше 23 тыс. файлов), и там каких только экзотических символов нет. Переименовать это малореально, да и впредь будут появляться подобные симолы.

А создавалка плейлистов должна всё это переваривать.
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 00:18 7
В цикле:
Bash
1
2
3
4
5
for %%? in (!N!) do (
 setlocal disabledelayedexpansion
 echo %%?,filename,%%B>>1.txt
 endlocal
)
Или использовать сначала вывод !N! без переноса
Bash
1
2
3
4
set /p x=!N!<nul >>1.txt
setlocal disabledelayedexpansion
echo ,filename,%%B >>1.txt
endlocal
Добавлено через 3 минуты
23 тысячи файлов лучше через VBS перелопатьте. Я как просплюсь код сюда скину, надеюсь оффтопом не будет. А пока просто объемный код мозГ создавать не в состоянии
1
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 00:52  [ТС] 8
FraidZZ, О, заработало! (первый вариант, второй не пробовал) Спасибо огромное!

Да ладно, написал уже на batе, роднее оно как-то, ближе, чем vbs...

Добавлено через 33 минуты
Второй вариант тоже работает.

Но всё равно это не годится. Дело в том, что снаружи этого FOR есть ещё один FOR, и если сделать
setlocal disabledelayedexpansion
endlocal,
то там тоже ломаются переменные. Как бы так обойтись без setlocal disabledelayedexpansion?
0
Dragokas
01.11.2013, 05:51
  #9

Не по теме:

sov44, экранирование 0-потока, чтобы представить 0 как строку а не служебную команду,
если ты об этом.

1
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 13:43 10
Никак. Без этого сожрет знаки !
Плюс ко всему, VBS быстрее в сотни раз. Честно. На 23 тысячи файлов это очень актуально.

Добавлено через 2 минуты
Хотя, приведите весь батник, посмотрим, что можно сделать
0
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 15:09  [ТС] 11
Нет, ну я ещё не сдаюсь. Добью батник (или он меня), возьмусь за вбсник.

Переписал я всё заново вообще без setlocal disabledelayedexpansion. Очередные вопросы:

1. Как заставить конструкцию FOR /F "DELIMS=" %%A IN ('DIR %BaseDir% /B /S /AD') DO () выдавать не только имена всех каталогов ниже, но и плюс к ним имя самого каталога %BaseDir%?

Или, если это невозможно, как снаружи цикла FOR вручную присвоить переменной %%A значение %BaseDir%?

2. Как организовать счётчик внутри цикла FOR не прибегая к setlocal enabledelayedexpansion?
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 15:34 12
Вот вам аналогичный сканер на VBS, все как обещал
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
ScanDir = CreateObject("Wscript.Shell").CurrentDirectory
SFIle = ScanDir & "\1.txt"
set FSO = CreateObject("Scripting.FileSystemObject")
 
With FSO.OpenTextFile(SFile, 8, 1)
 .Write "MPCPLAYLIST" & chr(10)
 .Close
End With
 
C = ScanFolders(ScanDir, 1)
Wscript.Quit
 
Function ScanFolders(SDir, Counter)
 set CurF = FSO.GetFolder(SDir)
 set WRT = FSO.OpenTextFile(SFile, 8, 1)
 For Each File In CurF.Files
   WRT.Write Counter & ",type, 0" & chr(10)
   WRT.Write Counter & ",filename," & File.Path & chr(10)
   Counter= Counter + 1
 Next
 WRT.Close
 NCount = Counter
 For Each Folder In Curf.SubFolders
  NCount = ScanFolders(Folder.Path, NCount)
 Next
 ScanFolders = NCount
End Function
Добавлено через 53 секунды
Цитата Сообщение от E30M20B20 Посмотреть сообщение
2. Как организовать счётчик внутри цикла FOR не прибегая к setlocal enabledelayedexpansion?
Через %%N%% попробуйте

Добавлено через 2 минуты
Вернее не просто %%N%%, а так
Bash
1
2
3
4
5
6
7
@echo off
set c=1
for %%A In (1 2 3 4 5 6 7 8) do (
 call set /a c=%%c%%+1
 call echo.%%c%%
)
pause
1
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 15:59  [ТС] 13
FraidZZ,

Код
@echo off
set c=1
for %%A In (1 2 3 4 5 6 7 8) do (
 call set /a c=%%c%%+1
 call echo.%%c%%
)
pause
А как её проверить? IF /I "%%N%%"=="1" (echo ляляля>PlayList.txt)

По первому своему вопросу разобрался - чтобы выводилась и текущая директория тоже, надо так:
FOR /F "DELIMS=" %%A IN ('DIR %BaseDir%* %BaseDir% /B /S /AD') DO ()

VBS не смотрел. Допишу BAT - возьмусь.
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 16:21 14
Можно вынести цикл в отдельную процедуру
Bash
1
2
3
4
5
6
FOR /F "DELIMS=" %%A IN ('DIR %BaseDir%* %BaseDir% /B /S /AD') DO call :Parse %%A
...
exit /b
:Parse
Здесь раскрываем как обычно, через %Н%, а переменую %%A получаем как %~1
exit /b
1
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 20:01  [ТС] 15
Здесь раскрываем как обычно, через %Н%, а переменую %%A получаем как %~1
Переменная %%A содержит "крышечки" (^), и они до парсера не доходят, съедаются.
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 20:40 16
Крышечки не передадите. Только VBS
0
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 21:45  [ТС] 17
Крышечки - это вообще тяжёлый случай.

Так. А если никуда данные не передавать, а передавать в парсер счётчик, там его проверять, и возвращать exit code? Но опять же непонятно что с ним дальше делать.

Код
FOR /F "DELIMS=" %%A IN ('DIR %BaseDir%* %BaseDir% /B /S /AD') DO (
  CALL :Parse
  IF ERRORLEVEL 1 (ECHO "бубубу">file.txt)
)
EXIT

:Parse
IF /I "%N%"=="1" (EXIT /B 1)
EXIT /B 0
Как-то так.

Добавлено через 12 минут
Цитата Сообщение от E30M20B20 Посмотреть сообщение
IF ERRORLEVEL 1
Гагага, я угадал! Всё, так всё работает!

Добавлено через 5 минут
Вот полный листинг. Всё проверено - работает. Но действительно очень медленно. Особенно там, где проверяется таблица расширений.

Конструктивно покритикуйте пжлст.

Код
@ECHO OFF

SET BaseDir=D:\3
rem SET BaseDir=\\IOMEGA-2TB\MUSICMP3

SET STARTTIME=%TIME:~,8%
IF "%STARTTIME:~,1%"==" " (SET STARTTIME=0%STARTTIME:~-7%)
SET STARTDATETIME=%DATE% %STARTTIME%

SET TIME1=%TIME:~,8%
IF "%TIME1:~,1%"==" " (SET TIME1=0%TIME1:~-7%)
CLS & ECHO. & ECHO  Создавалка плейлистов .mpcpl для Media Player Classic - Home Cinema
ECHO. & ECHO  Базовый каталог - %BaseDir%
ECHO. & ECHO  %TIME1% Убиваю существующие плейлисты...

REM Повторяем для всех директорий включая текущую и вложенные
FOR /F "DELIMS=" %%B IN ('DIR %BaseDir%* %BaseDir% /B /S /AD') DO (
  FOR /F %%I IN ("%%B") DO (
    IF EXIST %%B\%%~nI.mpcpl (DEL %%B\%%~nI.mpcpl)
  )
)

SET TIME2=%TIME:~,8%
IF "%TIME2:~,1%"==" " (SET TIME2=0%TIME2:~-7%)
CLS & ECHO. & ECHO  Создавалка плейлистов .mpcpl для Media Player Classic - Home Cinema
ECHO. & ECHO  Базовый каталог - %BaseDir%
ECHO. & ECHO  %TIME1% - %TIME2% Старые плейлисты убил.
ECHO  %TIME2% Создаю новые плейлисты...

REM Повторяем для всех директорий включая текущую и вложенные
FOR /F "DELIMS=" %%A IN ('DIR %BaseDir%* %BaseDir% /B /S /AD') DO (

  SET /A N=0

  REM Если текущая директория пустая, не делаем
  DIR %%A /B /S /A-D 2>NUL >NUL && (

    REM Повторяем для всех файлов во всех директориях включая вложенные
    FOR /F "DELIMS=" %%B IN ('DIR "%%A" /B /S /A-D') DO (

      REM Проверяем, есть ли расширение файла в списке
      FOR /F %%C IN ("%%B") DO (
        FOR %%D IN (.ac3, .dts, .aif, .aifc, .aiff, .alac, .amr, .ape, .apl, .au, .snd, .cda, .flac, .m4a, .m4b, .m4r, .aac, .mid, .midi, .rmi, .mka, .mp3, .mpa, .mp2, .m1a, .m2a, .mpc, .ofr, .ofs, .ogg, oga, .opus, .ra, .tak, .tta, .wav, .wma, .wv, .aob, .mlp) DO (
          IF "%%~xC"=="%%D" (

            REM Создаём запись в плейлисте
            CALL SET /A N=%%N%%+1
            CALL :111
            IF ERRORLEVEL 1 (ECHO MPCPLAYLIST>%%A\%%~nA.mpcpl)
            CALL ECHO.%%N%%,type,^0>>%%A\%%~nA.mpcpl
            CALL ECHO.%%N%%,filename,%%B >>%%A\%%~nA.mpcpl
          )
        )
      )
    )
  REM Если плейлист создался, конвертируем его в CP1251
  IF EXIST %%A\%%~nA.mpcpl (fdoswin.exe /OFF %%A\%%~nA.mpcpl %%A\%%~nA.mpcpl >NUL)
  )
)

SET TIME3=%TIME:~,8%
IF "%TIME3:~,1%"==" " (SET TIME3=0%TIME3:~-7%)
CLS & ECHO. & ECHO  Создавалка плейлистов .mpcpl для Media Player Classic - Home Cinema
ECHO. & ECHO  Базовый каталог - %BaseDir%
ECHO. & ECHO  %TIME1% - %TIME2% Старые плейлисты убил.
ECHO  %TIME2% - %TIME3% Новые плейлисты создал.

SET ENDTIME=%TIME:~,8%
IF "%ENDTIME:~,1%"==" " (SET ENDTIME=0%ENDTIME:~-7%)
SET ENDDATETIME=%DATE% %ENDTIME%
ECHO Set objShell=CreateObject^(^"Wscript.Shell^"^) > Interval.vbs
ECHO Interval = CDate^(CDate^(^"%ENDDATETIME%^"^) - CDate^(^"%STARTDATETIME%^"^)^) >> Interval.vbs
ECHO Wscript.Echo Interval >> Interval.vbs
FOR /F %%A IN ('CSCRIPT //NOLOGO "Interval.vbs"') DO SET INTERVAL=%%A:
DEL /Q Interval.vbs
SET INTERVAL=%INTERVAL:~0,8%
IF "%INTERVAL:~7,1%" == ":" (SET INTERVAL=0%INTERVAL:~0,7%)
IF "%INTERVAL:~2,1%" == "." (SET INTERVAL=Более суток) 
ECHO.
ECHO  Общее время работы ^> %STARTTIME% - %ENDTIME% = %INTERVAL%
ECHO.
EXIT

:111
IF /I "%N%"=="1" (EXIT /B 1)
EXIT /B 0
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 22:13 18
Я бы не делал проверку счетчиков, а просто сначала бы для каждого плейлиста вписывал MPCPLAYLIST, а потом файлы. И зачем 42 строка, непонятно. А так код прекрасен :-)
0
3 / 3 / 0
Регистрация: 31.10.2013
Сообщений: 25
01.11.2013, 22:50  [ТС] 19
Цитата Сообщение от FraidZZ Посмотреть сообщение
Я бы не делал проверку счетчиков, а просто сначала бы для каждого плейлиста вписывал MPCPLAYLIST, а потом файлы. И зачем 42 строка, непонятно. А так код прекрасен :-)
Дело в том, что не в каждой директории есть файлы, тем более с нужными расширениями. Проверяя счётчик я гарантированно создаю плейлист только если есть хотя бы один правильный файл.

42 строка помещает в переменную %%C очередное имя файла с полным путём, я потом в 44-й строке сравниваю значение из таблицы с %:~xC - расширением этого файла.

Кстати, 42 и 44 строки не годятся - только что обнаружил. Если в пути или имени файла есть хоть один пробел, то %:~C=="" Щас что-то буду с этим думать.

Добавлено через 5 минут
А, тю, ну так "DELIMS=" забыл.

42 строка правильнее так:
Код
      FOR /F "DELIMS=" %%C IN ("%%B") DO (
А заодно и 18-я строка тоже:
Код
  FOR /F "DELIMS=" %%I IN ("%%B") DO (
0
Pure Free Digital Ghost
4356 / 1795 / 350
Регистрация: 06.01.2013
Сообщений: 4,411
01.11.2013, 23:09 20
А почему Вы не хотите использовать %%~xB, а делаете сначала присваивание его в %%С?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.11.2013, 23:09

Поиск файлов с атрибутом "скрытый" ("hidden") на заданном дисковом томе с целью их дальнейшего удаления
Всем здравствуйте!!! Помогите пожалуйста создать батник. Задание: Поиск файлов с атрибутом...

"tokens=*" "съедает" одну строчку при обработке вывода результата выполнения команды ping :)
Друзья, нашел батничек для пинга узла и вывода инфо в файл, кое что подправил под себя, но остался...

Установить для пользователя значение "FALSE" параметра "PasswordExpires" командой WMIC
wmic useraccount where &quot;name='имя_пользователя' &quot; set passwordexpires=false это строка не работает

Разработать "универсальную" программу, позволяющую "динамически" изменять параметры окружения среды
Разработать &quot;универсальную&quot; программу позволяющую пользователю &quot;динамически&quot; (во время работы...

Применение "враппера" для параллельной обработки данных в нескольких циклах с "FOR"
День добрый! Взял отсюда код Dragokas, сделал параллельную работу двух for - вроде рад пока, но...

Запуск служб "Служба доступа к файлам" и "Клиент для сетей Microsoft" с использованием bat- или vbs-файла
Доброе время суток. Подскажите пожалуйста можно ли как нибудь запустить службы &quot;служба доступа к...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.