Asignar la salida de un programa a una variable con un archivo por lotes de MS
-
22-09-2019 - |
Pregunta
Necesito asignar la salida de un programa a una variable con un archivo por lotes de MS.
Así que en GNU Bash me gustaría utilizar VAR=$(application arg0 arg1)
. Necesito un comportamiento similar en Windows utilizando un archivo por lotes.
Algo así como set VAR=application arg0 arg1
.
Solución
Una forma es:
application arg0 arg1 > temp.txt
set /p VAR=<temp.txt
Otra es:
for /f %%i in ('application arg0 arg1') do set VAR=%%i
Tenga en cuenta que la primera %
en %%i
se utiliza para escapar de la %
después y se necesita cuando se utiliza el código anterior en un archivo por lotes en lugar de en la línea de comandos. Imagínese, su test.bat
tiene algo como:
for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%
Otros consejos
Como una adición a esta respuesta anterior , tubos pueden ser utilizados en el interior de un comunicado, se escaparon por un acento circunflejo:
for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i
@OP, puede utilizar para bucles para capturar el estado de retorno de su programa, si da salida a algo distinto de los números
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%
Al ejecutar: for /f %%i in ('application arg0 arg1') do set VAR=%%i
que estaba haciendo de error: %% i fue inesperado en este momento.
Como una solución, que tenía que ejecutar anteriormente como for /f %i in ('application arg0 arg1') do set VAR=%i
Además de la respuesta, no se puede utilizar directamente operadores de redirección de salida en el Set parte de bucle for
(por ejemplo, si quieres ocultar la salida estándar de error de un usuario y proporciona un mensaje de error más agradable) . En su lugar, usted tiene que 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 de mando en bucle de escritura de la hornada
Se podría utilizar una macro sencilla lotes para la captura de las salidas de comando, un poco como el comportamiento de la cáscara del golpe.
El uso de la macro es simple y se parece a
%$set% VAR=application arg1 arg2
Además, funciona incluso con tuberías
%$set% allDrives="wmic logicaldisk get name /value | findstr "Name""
Los usos macro la variable como una matriz y tiendas de cada línea en un índice separado.
En la muestra de %$set% allDrives="wmic logicaldisk
habrá creado 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
@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
Me escribió el guión que hace ping google.com cada 5 segundos y los resultados de explotación forestal 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