Сложное кодирование выхода в пакетном цикле for

Вопрос или проблема

Обращаем внимание на 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.

Оцените материал
Добавить комментарий

Капча загружается...