如何将每个变量从FOR循环输出到其自己的文件

时间:2019-08-08 16:12:57

标签: batch-file for-loop variables output

我正在尝试使用FOR循环运行查询,并将查询输出的每个结果变量行放入其自己的文件中。

我似乎无法让延迟的扩展变量按我希望的方式运行。

基本上,我正在查询安装在打印服务器上的打印机,我想要一个.bat作业,其中包含某些文本,并将结果输出到包含结果名称的多个文件中。

我认为问题是我没有正确转义某些字符,或者我错过了%或!变量或它们的某种组合。

@echo off
setlocal enabledelayedexpansion
FOR /F "tokens=1 delims=*" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (

    SET printer=%%G
    SET printers=!printers: =!
    SET printers=!printers:Name=!
    ECHO ^(
        @ECHO OFF
        ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO.
        ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"^)>>!printer!.bat
)

endlocal

预期结果应为名为PRINTERSHARENAME.bat的多个文件

每个包含:

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p "\\PRINTSERVER\PRINTERSHARENAME"

编辑

我将分享更多代码。 wmic输出包含必须删除的空格,所以这就是为什么我使用enabledelayedexpansion

EDIT2

这是我的wmic命令的输出(请注意,在上面的代码中我删除了结尾的空格,并在命令末尾加上了“名称”和空白行):

C:\Users\bleepbloop>wmic /node:PRNTSVR printer get name
Name
PRINTER1                          
PRINTER2                              
OFFICEPRINTER                        

EDIT3

好的,我已经接近了。这是使用以下答案重现的代码:

(
echo Here is my first line
echo Here is my second line
echo Here is my third line
)>"textfile.txt"

FOR /F "delims=" %%G IN ('TYPE textfile.txt') DO (
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
    )>%%G.bat
)

这可以按预期工作,并给我3个名为

的文件
Here is my first line.bat
Here is my second line.bat
Here is my third line.bat

但是现在我想从textfile.txt输出的变量中删除所有空格,为此,我认为我需要使用延迟扩展?

所以我想要

Hereismyfirstline.bat
Hereismysecondline.bat
Hereismythirdline.bat

我认为我需要通过使用enabledelayedexpansion并将以下内容插入到FOR循环中来做到这一点:

SET variable=%%G
SET variable=!variable: =!

,然后我必须将变量正确地插入到循环中。仍然不确定如何。

我想要文件

Hereismyfirstline.bat

包含

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismyfirstline

和下一个文件

Hereismysecondline.bat

包含:

@ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismysecondline

2 个答案:

答案 0 :(得分:1)

我建议此任务使用以下批处理代码:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
    for /F "eol=| delims=   " %%J in ("%%I") do (
        set Printer=%%~nxJ
        if defined Printer (
            echo @echo off
            echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
            echo echo/
            echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\%%~nxJ"
        )>"%%~nxJ.bat"
    )
)
endlocal

注意:在第二个delims=命令行上的for之后,必须为水平制表符,并且不能为Web浏览器根据HTML标准显示的一个或多个空格。制表符。

处理wmic的输出是有问题的,因为此应用程序输出的数据始终使用UTF-16 Little Endian编码进行Unicode编码,并且for对于正确处理此Unicode输出具有怪癖。有关更多详细信息,请参见例如How to correct variable overwriting misbehavior when parsing output?

外部for通过跳过包含标题wmic的第一行来处理Name的输出。对于所有其他非空行,即使在以分号开头非常不寻常的情况下,也要在将其余行分配给指定的循环变量I之前删除所有前导常规空格和水平制表符。打印机名称中不允许使用|,但可以使用;,尽管从未见过以;开头的打印机名称。

以水平制表符作为分隔符的内部for处理打印机名称,该名称可以包含一个或多个空格,但不能包含制表符。除去所有 trailing 水平制表符的打印机名称将分配给指定的循环变量J

剩余的字符串是带有后跟常规空格的打印机名称。 Windows通常会阻止创建带有尾随空格的文件。因此,仅使用打印机名称(不带空格)将Printer分配给环境变量%%~nxJ。但是此命令会保留打印机名称中的空格。

for处理wmic的输出引起的单回车会导致删除环境变量Printer,而不是用回车来定义。

因此,如果确实使用打印机名称定义了环境变量Printer,则该打印机名称不包含一个,一个或多个空格,但不包含前导空格/制表符,也不包含尾随空格/制表符,则可以使用来创建批处理文件分配给批处理文件中循环变量J的打印机名称,以及使用%%~nxJ分配给批处理文件名称的打印机名称。

因此,不需要延迟的环境变量扩展,这使得该批处理文件也可以用于包含感叹号的打印机名称。

另请参阅DosTips论坛主题ECHO. FAILS to give text or blank line - Instead use ECHO/,原因是写入已创建的批处理文件echo/而非echo.的原因。

此批处理代码在内部循环中使用delayed expansion来删除打印机名称中批处理文件名的所有空格。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
    for /F "eol=| delims=   " %%J in ("%%I") do (
        set "Printer=%%~nxJ"
        if defined Printer (
            setlocal EnableDelayedExpansion
            set "BatchFileName=!Printer: =!"
            (
                echo @echo off
                echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
                echo echo/
                echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\!Printer!"
            )>"!BatchFileName!.bat"
            endlocal
        )
    )
)
endlocal

运行整个文件名时用双引号括起来的批处理文件的文件名中有一个或多个空格绝对没有问题,就像其他文件/文件夹名称中包含空格或这些字符之一&()[]{}^=;!'+,`~ 。但是,第二个批处理文件代码证明,可以正确地创建打印机名称中带有感叹号的批处理文件,而文件名中不能包含空格。

由于在循环内使用了setlocalendlocal,因此此代码比第一个代码慢。阅读this answer,了解有关命令setlocalendlocal的详细信息,以及这两个命令在后台每次使用时会发生什么,使第二个变体比第一个变体慢。

注意:批处理文件中的打印机名称带有空格。只是批处理文件名没有空格。但这可以根据需要轻松更改。

答案 1 :(得分:0)

括号可以对命令进行分组,但不能拆分参数。因此,请执行以下操作,而不要使用ECHO (...

    SET printer=%%G
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"
    )>!printer!.bat

>>替换为>,这将为每台打印机创建新文件,而不是 向现有文件添加更多命令。

您也不需要延迟扩展,也许"delims="就足够了。 总体而言,您的代码可能会重写为:

FOR /F "delims=" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (
    (
        ECHO @ECHO OFF
        ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
        ECHO ECHO.
        ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
    )>%%G.bat
)