Пакет для L oop - Ошибка выполнения команды python - PullRequest
1 голос
/ 27 мая 2020

Я пытаюсь запустить это декодирование base64 в FOR l oop -

SETLOCAL EnableDelayedExpansion

FOR /F "tokens=1,2 delims= " %%a IN (file.txt) DO (
     FOR /F "tokens=* USEBACKQ" %%g IN (`echo %%a | python -m base64 -d`) do (SET "decode1=%%g")
<nul set /p =!decode1! >> new2.txt
echo. >> new2.txt
)

Я получаю сообщение об ошибке, что канал "|" было неожиданно в это время.

Если я запустил этот другой пример, он будет работать нормально -

FOR /F "tokens=1,2 delims= " %%a IN (file.txt) DO (
echo %%a | python -m base64 -d > temp.txt
set /p var1=<temp.txt
<nul set /p =!var1! >> new.txt
echo. >> new.txt
)

Я просто пытаюсь сразу вывести результат python в переменную вместо того, чтобы возиться, как в второй пример. Можно ли это сделать?

Вот структура моего file.txt. Это просто. В нем несколько строк (несколько сотен) с 2 столбцами base64, которые необходимо декодировать в файл new.txt с пробелом между каждым столбцом, как в file.txt.

file.txt

Q2FTZlpsZXhlR2dWNWV2Mkxsd0JQdw== Ylk5VEh3M1dRSFhqUHV2WjlMcURyZw==
ZDRhMHhHbndLTDBKa3A4S0piSlB2dw== NWxVODVSNEJUUVZpMGx0UHNERVJvQQ==
RHBHTEFfS0poWWlXbnI3c3NFUzlHQQ== RUcwb3dUWmNYM2UtMzBKVFhOWk1uQQ==
Z3RvanZRMUloMzhsYjkyVXNpNTZ1Zw== LW5rLXdndmYyYzRDLW9oNWg1Nk1Udw==

Ответы [ 2 ]

1 голос
/ 27 мая 2020

Основная проблема в вашем коде - это отсутствие экранирования, как показано в этот связанный ответ , а также этот связанный комментарий :

FOR /F "tokens=* USEBACKQ" %%g IN (`echo %%a | python -m base64 -d`) do (SET "decode1=%%g")

следует читать:

FOR /F "tokens=* USEBACKQ" %%g IN (`echo %%a ^| python -m base64 -d`) do (SET "decode1=%%g")

, чтобы скрыть трубу | из первой фазы синтаксического анализа, которая обрабатывает все for /F l oop определение.

Кроме того, рекомендую использовать set /p ="!decode1!", а не set /p =!decode1!, чтобы сохранить окружающие кавычки, которые могут присутствовать в значении переменной decode1.


В любом случае, я хочу предоставить альтернативный метод вашего подхода к преобразованию, на основе инструмента certutil, который доступен с Windows XP, я думаю:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_SEP= "                        & rem // (separator character or string for the output)
set "_TMP=%TEMP%\%~n0_%RANDOM%.tmp" & rem // (temporary file for conversion of single items)
set "_CHR=%TEMP%\%~n0_%RANDOM%.chr" & rem // (temporary file to hold just a given separator)

rem // Create a temporary file that only contains a single separator as specified:
> nul forfiles /P "%~dp0." /M "%~nx0" /C "cmd /V /C ^> 0x22!_CHR!0x22 echo(!_SEP!0x1A"
> nul copy "%_CHR%" /A + nul "%_CHR%" /B
rem // Loop through all non-empty lines read from the console input:
for /F "tokens=* eol= " %%L in ('more') do (
    rem // Explicitly deny wildcard characters that would cause problems with a `for` loop later:
    for /F "delims=*?<> eol=*" %%C in ("%%L") do if not "%%C"=="%%L" (
        >&2 echo "%%L" contains forbidden characters!
    ) else (
        rem // Loop through whitespace-separated items in the current line:
        set "FIRST=#"
        for %%I in (%%L) do (
            rem // Check current items against list of all valid characters for Base64 encoding:
            (
                for /F "delims=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= eol==" %%D in ("%%I") do rem/
            ) && (
                >&2 echo "%%I" is not valid Base64 encoding!
            ) || (
                rem // Actually perform the Base64 decoding of the current item:
                > "%_TMP%" echo(%%I
                > nul certutil -f -v -decode "%_TMP%" "%_TMP%"
                rem // Write the resulting data to the console output:
                if not defined FIRST type "%_CHR%"
                type "%_TMP%"
                set "FIRST="
            )
        )
        if not defined FIRST echo/
    )
)
rem // Clean up temporary files:
del "%_TMP%" "%_CHR%"

endlocal
exit /B

Этот скрипт, назовем его decode-b64-chunks.bat, читает в кодировке Base64 данные из консоли и записывает декодированные данные в консоль. Чтобы преобразовать образец входного файла file.txt из вашего вопроса в новый файл в текущем рабочем каталоге, используйте следующую командную строку:

decode-b64-chunks.bat < "file.txt" > "new.txt"

Результирующий файл с именем new.txt в конечном итоге будет содержать следующий текст :

CaSfZlexeGgV5ev2LlwBPw bY9THw3WQHXjPuvZ9LqDrg
d4a0xGnwKL0Jkp8KJbJPvw 5lU85R4BTQVi0ltPsDERoA
DpGLA_KJhYiWnr7ssES9GA EG0owTZcX3e-30JTXNZMnA
gtojvQ1Ih38lb92Usi56ug -nk-wgvf2c4C-oh5h56MTw

Приведенный выше скрипт содержит две конкретные части кода, которые я хочу go в:

  1. Явно отрицать символы подстановки, которые могут вызвать проблемы с for l oop позже:

        for /F "delims=*?<> eol=*" %%C in ("%%L") do if not "%%C"=="%%L" (
            >&2 echo "%%L" contains forbidden characters!
        ) else (
            …
        )
    

    %%L содержит текущую строку строки. Параметр delims в for /F l oop перечисляет все символы подстановки (* и ? хорошо известны, а < и > недокументированы). Таким образом, если текущая строка содержит один такой символ, for /F каким-то образом его токенизирует, поэтому его метапеременная %%C не равна исходной строке строки в %%L, тогда вся строка пропускается и появляется сообщение об ошибке возвращается.

    Причиной исключения таких строк является l oop for %%I in (%%L) do, который используется для обхода элементов, разделенных пробелами в строке. Стандартный for l oop (без переключателя /F) предназначен для l oop через файлы, но на самом деле он обращается к файловой системе только тогда, когда встречается хотя бы подстановочный знак, что я хочу предотвратить. .

  2. Проверить текущие элементы на соответствие списку всех допустимых символов для кодировки Base64:

                )
                    for /F "delims=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= eol==" %%D in ("%%I") do rem/
                ) && (
                    >&2 echo "%%I" is not valid Base64 encoding!
                ) || (
                    …
                )
    

    Параметр delims перечисляет все символы, разрешенные в кодировке Base64- закодированная строка. Теперь, если элемент %%I содержит только такие символы, это строка только с разделителями, которая for /F пропускается; если встречается любой другой символ, for /F обрабатывает текст, хотя ничего не происходит, так как в теле l oop содержится только rem/. В любом случае, я просто хочу знать, повторяется ли for /F или нет, потому что тогда я знаю, является ли обработанный элемент действительными данными в кодировке Base64.

    Подсказка здесь в том, что for /F (в отличие от любого другого for loops) сбрасывает код выхода, когда он повторяется хотя бы один раз, и устанавливает его, когда это не так. Условный оператор && выполняет следующий код только тогда, когда код выхода равен нулю, поэтому при итерации for /F l oop, что означает обнаружение запрещенного символа, в этом случае текущий элемент пропускается и появляется сообщение об ошибке возвращается. Условный оператор || выполняет следующий блок, когда код выхода не равен нулю, поэтому элемент содержит допустимые данные в кодировке Base64.

0 голосов
/ 27 мая 2020
python -c "import base64, sys; f=open('file.txt', 'rb'); [print(base64.b64decode(lines.split()[0]).decode(), base64.b64decode(lines.split()[1]).decode()) for lines in f]; f.close()" > new2.txt

Это позволяет избежать возни с с for l oop ... set /p et c. и позволяет Python читать file.txt и перенаправлять вывод на new2.txt. Если кодировка выходного файла является проблемой, возможно, Python также может выполнять запись.

Протестировано с Python 3.8, если это имеет значение.

...