Atribuir saída de um programa a uma variável usando um arquivo em lotes MS

290

Eu preciso atribuir a saída de um programa a uma variável usando um arquivo em lotes do MS.

Então, no shell GNU Bash eu usaria VAR=$(application arg0 arg1). Eu preciso de um comportamento semelhante no Windows usando um arquivo em lotes.

Algo como set VAR=application arg0 arg1.

initialZero
fonte

Respostas:

433

Uma maneira é:

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

Outro é:

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

Note-se que o primeiro %no %%ié usado para escapar do %após-lo e é necessária para utilizar o código acima em um arquivo de lote em vez de na linha de comando. Imagine, você test.battem algo como:

for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%
Carlos Gutiérrez
fonte
11
Este é um grande truque, eu me pergunto por que ele não funciona com um cano #
K Bill Bill
25
Isso funciona apenas para a saída, que é uma única linha de texto (linhas subsequentes omitidas após a primeira quebra de linha).
precisa saber é o seguinte
20
@Machta, o tubo deve ser escapado com um sinal ^ antes dele, dentro da expressão em parênteses. Exemplo:for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"
Emanuele Del Grande
8
Não trabalhe para alinhar com espaços. Por exemplo: para / f %% i in ('ver') defina VAR = %% i. Como escreveu @Renat, deve adicionar "tokens = *"
Yura Shinkarev 13/01
2
@GroovyCakes Sua pergunta sobre várias linhas na saída é respondida por esta resposta em uma pergunta duplicada
icc97 31/17/17
67

Como complemento à resposta anterior , os tubos podem ser usados ​​dentro de uma instrução for, escapada por um símbolo de sinal de intercalação:

    for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i
Renat
fonte
1
Dois pontos importantes: use tokens para capturar e intercalar para escapar do cano.
Christopher Oezbek
6
Versão equivalente que funciona na CLI e pode ser copiada e colada para facilitar a correção: for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %iMas, em geral, ela usebackqdeve ser usada para manipular comandos complexos.
Amit Naidu
Tokens eram necessários para manipular espaços na saída.
Mark Ingram
Cotações funcionar tão bem para mim, como este: for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i. Mais fácil para mim se não houver aspas no próprio comando.
Paul
10

@OP, você pode usar loops para capturar o status de retorno do seu programa, se ele gerar algo diferente de números

ghostdog74
fonte
8

supondo que a saída do seu aplicativo seja um código de retorno numérico, você pode fazer o seguinte

application arg0 arg1
set VAR=%errorlevel%
akf
fonte
5
Infelizmente, a saída é uma string.
initialZero
Está bem. manterei isso para a posteridade, mas dê uma olhada no link do @ jdigital, que fala sobre a saída de tubulação para um arquivo temporário.
akf
1
A saída do programa para stdout e stderr é diferente do valor de retorno inteiro. Um programa pode retornar um valor inteiro, como no exemplo acima, ao mesmo tempo em que envia uma string para o console (ou redireciona para um arquivo ou outro local). Eles não são mutuamente exclusivos e são dois conceitos diferentes.
David Rector
7

Em execução: for /f %%i in ('application arg0 arg1') do set VAR=%%ieu estava recebendo um erro: %% i foi inesperado no momento. Como uma correção, eu tive que executar acima comofor /f %i in ('application arg0 arg1') do set VAR=%i

Munish Mehta
fonte
9
Em um arquivo de lote que você precisa %%e fora de um arquivo de lote em uma linha de comando que você precisa%
Jerry Jeremias
2

Além da resposta, você não pode usar diretamente os operadores de redirecionamento de saída na parte definida do forloop (por exemplo, se você deseja ocultar a saída stderror de um usuário e fornecer uma mensagem de erro melhor). Em vez disso, você deve escapar deles com um caractere de intercalação ( ^):

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

Referência: Redirecionar a saída do comando para loop for script em lote

Kubo2
fonte
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
rcm
fonte
(plus1) para explicação dos backticks
Sandburg
1

Você pode usar uma macro em lote para capturar simples as saídas de comando, um pouco como o comportamento do shell bash.

O uso da macro é simples e parece

%$set% VAR=application arg1 arg2

E funciona mesmo com tubos

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

A macro usa a variável como uma matriz e armazena cada linha em um índice separado.
Na amostra de %$set% allDrives="wmic logicaldisklá serão criadas as seguintes variáveis:

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 usá-lo, não é importante entender como a própria macro funciona.

O exemplo 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
jeb
fonte
0

Eu escrevi o script que faz ping no google.com a cada 5 segundos e registra os resultados com o tempo atual. Aqui você pode encontrar saída para as variáveis ​​"commandLineStr" (com í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
Ja Vy
fonte