Вопрос или проблема
Обращаем внимание на https://superuser.com/a/1508668/1884857
В моем коде я добавил код Vomit IT в цикл for. Однако код останавливается на строке:
ECHO [int]$Calculation.split("%MathType%")[0] %MathType% [int]$Calculation.split("%MathType%")[1] >> "%PSScript%"
Вывод ошибки при выполнении пакета:
[0] было неожиданным в это время.
Мой вопрос: как сделать так, чтобы код работал в цикле for (например, перебор файлов в папке)?
Я пробовал различные методы экранирования, например:
ECHO [int]$Calculation.split("!MathType!")[0] !MathType! [int]$Calculation.split("!MathType!")[1] >> "!PSScript!"
К сожалению, все еще безуспешно.
Буду признателен за любые идеи.
Это оригинальный код из другого поста:
SET "Calculation=3*1073741824"
SET "MathType=*"
SET PSScript=%temp%\PS~MathTemp.ps1
IF EXIST "%PSScript%" DEL /Q /F "%PSScript%"
ECHO $Calculation = "%Calculation%" > "%PSScript%"
ECHO [int]$Calculation.split("%MathType%")[0] %MathType% [int]$Calculation.split("%MathType%")[1] >> "%PSScript%"
For /F "Delims=" %%I IN (`Powershell -ExecutionPolicy Bypass -Command "& '%PSScript%'"`) Do Set "nCalc=%%I"
Редактировать: @io-io решил это! Для полноты картины, вот мой весь скрипт. Он сканирует все видеофайлы в списке файлов и обрабатывает их с помощью ffmpeg.
REM Измените кодировку консоли на UTF-8 (для северных символов).
chcp 65001 | echo/
set filelist=%1
echo %filelist%
REM Определите символ ESC для экранирования
for /f %%d in ('echo prompt $E ^| cmd') do (set "ESC=%%d")
REM Перебор всех видеофайлов в отдельном списке файлов
for /f "usebackq tokens=*" %%a in ("%filelist%") do (
call :StartTimer
set Bytes=%%~za
REM Код временной метки зависит от локальных настроек на компьютере
set Timestamp=%%~ta
set TSYYYY=!Timestamp:~6,4!
set TSYY=!Timestamp:~8,2!
set TSMM=!Timestamp:~3,2!
set TSDD=!Timestamp:~0,2!
set TSHR=!Timestamp:~11,2!
set TSMIN=!Timestamp:~14,2!
set TSDato=!TSYY!!TSMM!!TSDD!
set TSTid=!TSHR!!TSMIN!
REM Отображение информации о входном файле
echo !ESC![92;103mInputfile="%%~fa"!ESC![0m
echo !ESC![92;103mРазмер входного файла=!Bytes! Bytes!ESC![0m
REM Конвертировать в MP4, если необходимо, и сжать в поддержку формата HEVC для iPhone
echo !ESC![91mКонвертировать файл %%~xa в формат MP4 и сжать в формат HEVC, поддерживаемый iPhone!ESC![0m
ffmpeg -n -hide_banner -loglevel quiet -i "%%~fa" -vcodec libx265 -vsync 0 -vtag hvc1 -crf 28 "%%~dpna_!TSDato!-!TSTid!.mp4"
REM Сбросить команды консоли после выполнения ffmpeg
chcp 65001 | echo/
REM Найти размер нового файла
FOR /F "tokens=*" %%b IN ("%%~dpna_!TSDato!-!TSTid!.mp4") DO set OutBytes=%%~zb
**REM Найти коэффициент сжатия нового и старого файла
SET "Calculation=!OutBytes!/!Bytes!"
SET "MathType=/"
SET PSScript=%temp%\PS~MathTemp.ps1
IF EXIST "!PSScript!" DEL /Q /F "!PSScript!"
ECHO $Calculation = "!Calculation!" > "!PSScript!"
ECHO [int]$Calculation.split("!MathType!"^)[0] !MathType! [int]$Calculation.split("!MathType!"^)[1] >> "!PSScript!"
FOR /F "USEBACKQ DELIMS=" %%c IN (`Powershell -ExecutionPolicy Bypass -Command "& '!PSScript!'"`) DO SET "Compression=%%c"**
REM Отображение сводки по сжатию
echo !ESC![42mСводка!ESC![0m
echo !ESC![32mInputfile="%%~fa"!ESC![0m
echo !ESC![32mРазмер входного файла=!Bytes! Bytes!ESC![0m
echo !ESC![32mOutputfile="%%~dpna_!TSDato!-!TSTid!.mp4"!ESC![0m
echo !ESC![32mРазмер выходного файла=!OutBytes! Bytes!ESC![0m
echo !ESC![32mКоэффициент сжатия=!Compression!!ESC![0m
echo !ESC![42mОптимизация файла "%%~a" завершена!ESC![0m
REM Очистка. Если новый файл создан, удалить оригинальный файл
if NOT exist "%%~dpna_!TSDato!-!TSTid!.mp4" (
echo !ESC![33mОптимизация не была выполнена!ESC![0m
) else (
del "%%~fa"
echo !ESC![47;91mОригинальный файл был УДАЛЕН!ESC![0m
)
call :StopTimer
call :DisplayTimerResult
REM pause >nul
);=
echo. & echo Все файлы оптимизированы! & endlocal
REM https://stackoverflow.com/questions/4313897/timer-in-windows-batch-file
:StartTimer
:: Сохранить время начала
set StartTIME=%TIME%
for /f "usebackq tokens=1-4 delims=:., " %%f in (`echo %StartTIME: =0%`) do set /a Start100S=1%%f*360000+1%%g*6000+1%%h*100+1%%i-36610100
goto :EOF
:StopTimer
:: Получить конечное время
set StopTIME=%TIME%
for /f "usebackq tokens=1-4 delims=:., " %%f in (`echo %StopTIME: =0%`) do set /a Stop100S=1%%f*360000+1%%g*6000+1%%h*100+1%%i-36610100
:: Проверка перехода через полночь. Если да, добавьте 1 день=8640000 сотых секунды
if %Stop100S% LSS %Start100S% set /a Stop100S+=8640000
set /a TookTime=%Stop100S%-%Start100S%
set TookTimePadded=0%TookTime%
goto :EOF
:DisplayTimerResult
:: Показать время начала/остановки/разницу
echo Начато: %StartTime%
echo Остановлено: %StopTime%
echo Прошедшее время: %TookTime:~0,-2%.%TookTimePadded:~-2% секунд
goto :EOF```
@echo off
set "_Math=*"
set "_Calc=3*1073741824"
set "_PSSctr=%tmp%\PS~MathTemp.ps1"
2>nul del /q /f "%_PSSctr%"
> "%_PSSctr%" (
echo/$Calc = "%_Calc%"
echo/[int]$Calc.split("%_Math%"^)[0] %_Math% [int]$Calc.split("%_Math%"^)[1]
)
For /F "Usebackq Delims=" %%i in (`
Powershell -ExecutionPolicy Bypass -Command "& '%_PSSctr%'"
`) do set "_nCalc=%%~i"
echo/%_nCalc%
1. Вы внесли изменения в оригинальный код, изменив " ' "
на " ` "
в выполнении оригинального For /F
цикла изменили (' ... ')
на (` ... `)
2. Экранирования, которое вам нужно, находится в echo ...
, где он содержит закрывающий )
, и только в закрытии ^)
, кроме того, если вы собираетесь использовать `
, добавьте Usebackq
в вашем For /f
цикле
Я хочу изучить кодирование, но пока это кажется мне чем-то фантастическим и очень сложным.
Ответ или решение
Использование сложного экранирования в цикле for в пакетных файлах
В этой статье мы рассмотрим проблему, с которой столкнулся разработчик при попытке выполнить скрипт PowerShell в цикле for
пакетного файла. Основная проблема заключается в правильном экранировании специальных символов для успешного выполнения сценария на PowerShell. Мы также изучим, как решить эту проблему при обработке файлов, используя предоставленный код.
Проблема
Исходный код, который привёл к ошибке [0] was unexpected at this time
, включает строку с вызовом PowerShell:
ECHO [int]$Calculation.split("%MathType%")[0] %MathType% [int]$Calculation.split("%MathType%")[1] >> "%PSScript%"
Ошибка возникла из-за того, что интерпретатор Windows не смог корректно обработать комбинации символов и экранирования.
Решение
Для того чтобы избежать этой ошибки, важно правильно управлять экранированием и использовать верные конструкции. Пример исправленного кода:
@echo off
set "_Math=*"
set "_Calc=3*1073741824"
set "_PSSctr=%temp%\PS~MathTemp.ps1"
2>nul del /q /f "%_PSSctr%"
> "%_PSSctr%" (
echo/$Calc = "%_Calc%"
echo/[int]$Calc.split("%_Math%"^)[0] %_Math% [int]$Calc.split("%_Math%"^)[1]
)
For /F "Usebackq Delims=" %%i in (`
Powershell -ExecutionPolicy Bypass -Command "& '%_PSSctr%'"
`) do set "_nCalc=%%~i"
echo/%_nCalc%
В приведенном коде мы используем ^)
для экранирования закрывающей круглой скобки, что позволяет интерпретатору корректно воспринимать конструкцию как часть команды.
Цикл по файлам
Если вы хотите использовать этот код в цикле для обработки файлов в определенной директории, вот пример, как это сделать:
@echo off
set "filelist=file_list.txt" REM Укажите файл со списком
set "_Math=*"
REM Основной процесс проходит по каждому файлу в списке
for /f "usebackq tokens=*" %%a in ("%filelist%") do (
set "_Calc=3*1073741824"
set "_PSSctr=%temp%\PS~MathTemp.ps1"
2>nul del /q /f "%_PSSctr%"
> "%_PSSctr%" (
echo/$Calc = "%_Calc%"
echo/[int]$Calc.split("%_Math%"^)[0] %_Math% [int]$Calc.split("%_Math%"^)[1]
)
For /F "usebackq delims=" %%i in (`
Powershell -ExecutionPolicy Bypass -Command "& '%_PSSctr%'"
`) do set "_nCalc=%%~i"
echo/Processed file: %%a with result: !_nCalc!
)
Заключение
В этой статье мы разобрали ключевые аспекты работы с вложенными командами PowerShell в пакетных скриптах. Убедитесь, что ваше экранирование выполнено корректно, чтобы избежать неожиданных ошибок, и используйте конструкции, ориентированные на специфику вашего скрипта. Правильное понимание этих принципов поможет вам более эффективно управлять скриптами в Windows и обеспечит надежное выполнение задач.
Эта информация может оказаться полезной разработчикам, стремящимся усовершенствовать свои навыки в написании пакетных файлов и эффективной автоматизации процессов в Windows.