批处理循环-运行python命令时出错

时间:2020-05-27 01:01:37

标签: python windows for-loop batch-file cmd

我正在尝试在FOR循环中运行此base64解码-

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 个答案:

答案 0 :(得分:1)

您的代码中的主要问题是,this related answerthis related comment中也都显示了转义:

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

此外,我建议使用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

上面的脚本包含我要输入的代码的两个特定部分:

  1. 明确拒绝通配符,这些通配符会在以后导致for循环出现问题:

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

    %%L包含当前行字符串。 delims循环的for /F选项列出了所有通配符(*?是众所周知的,而<>是未记录的通配符) )。因此,如果当前行包含一个这样的字符,for /F将以某种方式标记它,因此其元变量%%C不等于%%L中的原始行字符串,则整行被跳过并返回错误消息。

    排除此类行的原因是循环for %%I in (%%L) do,该循环用于遍历一行中用空格分隔的项目。标准的for循环(无/F开关)旨在循环遍历文件,但实际上,它仅在遇到至少通配符时才访问文件系统,这是我要防止的。 / p>

  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处理文本,尽管由于循环正文中仅存在rem/,所以没有任何反应。无论如何,我只想知道for /F是否迭代,因为那样我就知道所处理的项是否为有效的Base64编码数据。

    这里的线索是for /F(与任何其他for循环相反)在至少重复一次时重置退出代码,而在不重复一次时设置退出代码。仅当退出代码为零时,条件运算符&&才执行以下代码,因此,当迭代for /F循环时,这意味着遇到了一个禁止的字符,在这种情况下,当前项目被跳过,并出错消息返回。当退出代码不为零时,条件运算符||执行以下块,因此该项目包含有效的Base64编码数据。

答案 1 :(得分:0)

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循环... set /p等来摆弄 ,并让Python读取file.txt并将输出重定向到{{1 }}。如果输出文件编码是一个问题,那么Python也许也可以写。

如果有关系,请在Python 3.8上进行测试。