Asigne la salida de un programa a una variable utilizando un archivo por lotes MS


290

Necesito asignar la salida de un programa a una variable usando un archivo por lotes MS.

Entonces, en GNU Bash shell, usaría VAR=$(application arg0 arg1). Necesito un comportamiento similar en Windows usando un archivo por lotes.

Algo así como set VAR=application arg0 arg1.

Respuestas:


433

Una forma es:

application arg0 arg1 > temp.txt
set /p VAR=<temp.txt

Otro es:

for /f %%i in ('application arg0 arg1') do set VAR=%%i

Tenga en cuenta que el primero %en %%ise utiliza para escapar a la %vez que se necesita y cuando se utiliza el código anterior en un archivo por lotes en lugar de en la línea de comandos. Imagina, tu test.battiene algo como:

for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%

11
Este es un gran truco, me pregunto por qué no funciona con una tubería
Bill K

25
Esto solo funciona para la salida, que es una sola línea de texto (líneas posteriores omitidas después del primer salto de línea).
GroovyCakes

20
@Machta, la tubería debe escaparse con un signo ^ antes, dentro de la expresión en parens. Ejemplo:for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"
Emanuele Del Grande

8
No trabaje para línea con espacios. Por ejemplo: para / f %% i en ('ver') configure VAR = %% i. Como escribió @Renat, debería agregar "tokens = *"
Yura Shinkarev

2
@GroovyCakes Su pregunta sobre varias líneas en la salida se responde con esta respuesta en una pregunta duplicada
icc97

67

Como una adición a esta respuesta anterior , las tuberías se pueden usar dentro de una declaración for, escapada por un símbolo de intercalación:

    for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i

1
Dos puntos importantes: use fichas para capturar y evitar escapar de la tubería.
Christopher Oezbek

66
Versión equivalente que funciona en la CLI y se puede copiar y pegar para facilitar los ajustes: for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %iPero, en general, usebackqdebe usarse para manejar comandos complejos.
Amit Naidu

Se necesitaban tokens para manejar espacios en la salida.
Mark Ingram

Cotizaciones funcionan tan bien para mí, como este: for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i. Más fácil para mí si no hay comillas en el comando en sí.
Paul

10

@OP, puede usar bucles para capturar el estado de retorno de su programa, si genera algo distinto de números


8

suponiendo que la salida de su aplicación es un código de retorno numérico, puede hacer lo siguiente

application arg0 arg1
set VAR=%errorlevel%

55
Desafortunadamente, la salida es una cadena.
initialZero

Okay. Mantendré esto para la posteridad, pero eche un vistazo al enlace de @ jdigital, que habla sobre la salida de tuberías a un archivo temporal.
akf

1
La salida del programa a stdout y stderr es diferente de su valor de retorno entero. Un programa puede devolver un valor entero como en el ejemplo anterior, al tiempo que envía una cadena a la consola (o redirige a un archivo u otro lugar). No son mutuamente excluyentes y son dos conceptos diferentes.
David Rector

7

Al ejecutar: for /f %%i in ('application arg0 arg1') do set VAR=%%irecibía un error: %% era inesperado en este momento. Como solución, tuve que ejecutar arriba comofor /f %i in ('application arg0 arg1') do set VAR=%i


99
En un archivo por lotes que necesita %%y fuera de un archivo por lotes en una línea de comando que necesita%
Jerry Jeremiah

2

Además de la respuesta, no puede usar directamente operadores de redirección de salida en la parte establecida del forbucle (por ejemplo, si desea ocultar la salida de stderror de un usuario y proporcionar un mensaje de error más agradable). En cambio, debes escapar de ellos con un carácter de intercalación ( ^):

for /f %%O in ('some-erroring-command 2^> nul') do (echo %%O)

Referencia: Redirigir la salida del comando para el bucle del script por lotes


1
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION

REM Prefer backtick usage for command output reading:
REM ENABLEDELAYEDEXPANSION is required for actualized
REM  outer variables within for's scope;
REM within for's scope, access to modified 
REM outer variable is done via !...! syntax.

SET CHP=C:\Windows\System32\chcp.com

FOR /F "usebackq tokens=1,2,3" %%i IN (`%CHP%`) DO (
    IF "%%i" == "Aktive" IF "%%j" == "Codepage:" (
        SET SELCP=%%k
        SET SELCP=!SELCP:~0,-1!
    )
)
echo actual codepage [%SELCP%]

ENDLOCAL

(plus1) para explicación de backticks
Sandburg

1

Puede usar una macro por lotes para capturar fácilmente las salidas de comandos, un poco como el comportamiento del shell bash.

El uso de la macro es simple y parece

%$set% VAR=application arg1 arg2

Y funciona incluso con tuberías.

%$set% allDrives="wmic logicaldisk get name /value | findstr "Name""

La macro usa la variable como una matriz y almacena cada línea en un índice separado.
En la muestra de %$set% allDrives="wmic logicaldiskallí se crearán las siguientes variables:

allDrives.Len=5
allDrives.Max=4
allDrives[0]=Name=C:
allDrives[1]=Name=D:
allDrives[2]=Name=F:
allDrives[3]=Name=G:
allDrives[4]=Name=Z:
allDrives=<contains the complete text with line feeds>

Para usarlo, no es importante entender cómo funciona la macro en sí.

El ejemplo completo

@echo off
setlocal

call :initMacro

%$set% ipOutput="ipconfig"
call :ShowVariable ipOutput
echo First line is %ipOutput[0]%

echo( 
%$set% driveNames="wmic logicaldisk get name /value | findstr "Name""
call :ShowVariable driveNames

exit /b

:ShowVariable
setlocal EnableDelayedExpansion
for /L %%n in (0 1 !%~1.max!) do (
    echo %%n: !%~1[%%n]!
)
echo(
exit /b

:initMacro
if "!!"=="" (
    echo ERROR: Delayed Expansion must be disabled while defining macros
    (goto) 2>nul
    (goto) 2>nul
)
(set LF=^
%=empty=%
)
(set \n=^^^
%=empty=%
)

set $set=FOR /L %%N in (1 1 2) dO IF %%N==2 ( %\n%
    setlocal EnableDelayedExpansion                                 %\n%
    for /f "tokens=1,* delims== " %%1 in ("!argv!") do (            %\n%
        endlocal                                                    %\n%
        endlocal                                                    %\n%
        set "%%~1.Len=0"                                            %\n%
        set "%%~1="                                                 %\n%
        if "!!"=="" (                                               %\n%
            %= Used if delayed expansion is enabled =%              %\n%
                setlocal DisableDelayedExpansion                    %\n%
                for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                if "!!" NEQ "" (                                    %\n%
                    endlocal                                        %\n%
                    )                                               %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set pathExt=:                                       %\n%
                set path=;                                          %\n%
                set "line=!line:^=^^!"                              %\n%
                set "line=!line:"=q"^""!"                           %\n%
                call set "line=%%line:^!=q""^!%%"                   %\n%
                set "line=!line:q""=^!"                             %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") do (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") Do (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L" !                      %\n%
                        if %%C == 0 (                               %\n%
                            set "%%~1=%%~L" !                       %\n%
                        ) ELSE (                                    %\n%
                            set "%%~1=!%%~1!!LF!%%~L" !             %\n%
                        )                                           %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        ) ELSE (                                                    %\n%
            %= Used if delayed expansion is disabled =%             %\n%
            for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") DO (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") DO (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L"                        %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        )                                                           %\n%
        set /a %%~1.Max=%%~1.Len-1                                  %\n%
)                                                                   %\n%
    ) else setlocal DisableDelayedExpansion^&set argv=

goto :eof

0

Escribí el script que hace ping a google.com cada 5 segundos y registrando los resultados con la hora actual. Aquí puede encontrar la salida a las variables "commandLineStr" (con índices)

@echo off

:LOOPSTART

echo %DATE:~0% %TIME:~0,8% >> Pingtest.log

SETLOCAL ENABLEDELAYEDEXPANSION
SET scriptCount=1
FOR /F "tokens=* USEBACKQ" %%F IN (`ping google.com -n 1`) DO (
  SET commandLineStr!scriptCount!=%%F
  SET /a scriptCount=!scriptCount!+1
)
@ECHO %commandLineStr1% >> PingTest.log
@ECHO %commandLineStr2% >> PingTest.log
ENDLOCAL

timeout 5 > nul

GOTO LOOPSTART
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.