Como obtenho o resultado de um comando em uma variável no windows?

132

Eu estou procurando obter o resultado de um comando como uma variável em um script em lotes do Windows (veja como obter o resultado de um comando no bash para o equivalente de script do bash). É preferível uma solução que funcione em um arquivo .bat, mas outras soluções comuns de script do Windows também são bem-vindas.

John Meagher
fonte
9
John, é ridiculamente difícil encontrar essa pergunta muito útil. Você poderia adicionar frases alternativas como Como capturar a saída de um programa em uma variável em um arquivo em lotes do Windows?
Piotr Dobrogost
3
O Google exibiu esta página em 3º lugar.
René Nyffenegger 6/12/12
1
Possível duplicata do Windows Output Assign lote de um programa para uma variável
Michael Freidgeim
@MichaelFreidgeim, na verdade, essa pergunta foi feita 2 anos antes dessa duplicata - mas há várias duplicatas dessa pergunta. Veja os comentários em stackoverflow.com/questions/6359820/…
icc97
1
@ icc97, "Possível duplicata" é uma maneira de limpar - fechar perguntas semelhantes e manter uma com as melhores respostas. A data não é essencial. Consulte meta.stackexchange.com/questions/147643/… Se você concorda que isso requer esclarecimentos, vote em meta.stackexchange.com/questions/281980/… Se você encontrar várias duplicatas, escolha uma como canônica e vote para fechar outras. .
Michael Freidgeim

Respostas:

34

Se você precisar capturar toda a saída do comando, poderá usar um lote como este:

@ECHO OFF
IF NOT "%1"=="" GOTO ADDV
SET VAR=
FOR /F %%I IN ('DIR *.TXT /B /O:D') DO CALL %0 %%I
SET VAR
GOTO END

:ADDV
SET VAR=%VAR%!%1

:END

Todas as linhas de saída são armazenadas em VAR separadas por "!".

@ John: existe algum uso prático para isso? Eu acho que você deve assistir ao PowerShell ou qualquer outra linguagem de programação capaz de executar tarefas de script facilmente (Python, Perl, PHP, Ruby)

PabloG
fonte
A resposta em linha única resolverá o caso específico que tenho. Eu apenas imaginei que havia uma opção de várias linhas (ou uma opção de linha única mais fácil). Eu acho que as capacidades dos arquivos bat simplesmente não são tão boas. A necessidade disso é que os scripts bat envolvam os aplicativos Java. Construindo caminhos de classe principalmente.
John Meagher
Tenha muito cuidado com isso. O GWT também tentou usar arquivos em lote para iniciar o Java com caminhos de classe específicos, que falharam horrivelmente assim que você chegou aos diretórios com caracteres não ASCII (nesse caso, era minha casa :)). Desde então, eles reescreveram isso com o VBS.
Joey
25
existe algum uso prático para isso? Você está de brincadeira? Isso é usado o tempo todo em outros shells (acho que todos os GNU / Linux) e é muito útil.
Piotr Dobrogost 22/10/11
1
@PiotrDobrogost Acho que o que ele estava tentando dizer era que os scripts do bash são uma relíquia horrível do passado (você precisa usar um loop for apenas para capturar a saída de um programa? Sério?), E se você chegar ao ponto onde você precisar usar variáveis, use algo mais moderno como o PowerShell.
Ajedi32
3
Existe um uso prático, na verdade ... meio. Eu quero usar um script do PowerShell para encontrar um caminho específico do Visual Studio, mas o que eu preciso desse caminho é um arquivo em lotes que define vários envios para que eu possa chamar editbin ... Então, eu preciso encontrar o caminho e devolvê-lo à instância de chamada cmdpara que eu possa executá-lo lá. ... Sim, isso é tão terrível quanto parece. O Visual Studio me faz querer chorar às vezes. @ Ajedi32 Acho que você quis dizer que scripts em lote são uma relíquia horrível do passado. ;)
jpmc26
85

O humilde para o comando acumulou algumas capacidades interessantes ao longo dos anos:

D:\> FOR /F "delims=" %i IN ('date /t') DO set today=%i
D:\> echo %today%
Sat 20/09/2008

Observe que "delims=" substitui o espaço padrão e os delimitadores de tabulação para que a saída do comando date seja devorada ao mesmo tempo.

Para capturar a saída de várias linhas, ainda pode ser essencialmente uma linha (usando a variável lf como delimitador na variável resultante):

REM NB:in a batch file, need to use %%i not %i
setlocal EnableDelayedExpansion
SET lf=-
FOR /F "delims=" %%i IN ('dir \ /b') DO if ("!out!"=="") (set out=%%i) else (set out=!out!%lf%%%i)
ECHO %out%

Para capturar uma expressão canalizada, use ^|:

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
atrasado
fonte
1
Como na resposta de @ PabloG, isso funcionará apenas para obter a última linha de saída do comando "date / t" neste caso.
John Meagher
11
Eu achei a sua resposta ao trabalho apenas quando eu usei sinais de porcentagem duplo, isto éFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski
18
@Rabarberski: Se você digitar um forcomando diretamente na linha de comando, use um único %. Se você o usar em um arquivo em lotes, use %%.
indiv 22/09
@tardate: Você poderia dizer como será o script, se o comando precisar ser passado com argumento %, por exemplo:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k
1
@degenerate O comando é válido desde que o datecomando usado venha do Cygwin. Eu concordo que eu deveria ter mencionado isso.
dma_k
24

Para obter o diretório atual, você pode usar isto:

CD > tmpFile
SET /p myvar= < tmpFile
DEL tmpFile
echo test: %myvar%

Ele está usando um arquivo temporário, portanto, não é o mais bonito, mas certamente funciona! 'CD' coloca o diretório atual em 'tmpFile', 'SET' carrega o conteúdo de tmpFile.

Aqui está uma solução para várias linhas com "array":

@echo off

rem ---------
rem Obtain line numbers from the file
rem ---------

rem This is the file that is being read: You can replace this with %1 for dynamic behaviour or replace it with some command like the first example i gave with the 'CD' command.
set _readfile=test.txt

for /f "usebackq tokens=2 delims=:" %%a in (`find /c /v "" %_readfile%`) do set _max=%%a
set /a _max+=1
set _i=0
set _filename=temp.dat

rem ---------
rem Make the list
rem ---------

:makeList
find /n /v "" %_readfile% >%_filename%

rem ---------
rem Read the list
rem ---------

:readList
if %_i%==%_max% goto printList

rem ---------
rem Read the lines into the array
rem ---------
for /f "usebackq delims=] tokens=2" %%a in (`findstr /r "\[%_i%]" %_filename%`) do set _data%_i%=%%a
set /a _i+=1
goto readList

:printList
del %_filename%
set _i=1
:printMore
if %_i%==%_max% goto finished
set _data%_i%
set /a _i+=1
goto printMore

:finished

Mas você pode considerar mudar para outro shell mais poderoso ou criar um aplicativo para esse material. Está ampliando bastante as possibilidades dos arquivos em lote.

Atividade maligna
fonte
Existe uma variação que funcione para capturar várias linhas do comando?
John Meagher
6
Para obter o diretório atual, você pode usar echo% CD%
Joe
9

você precisa usar o SETcomando com parâmetro /Pe direcionar sua saída para ele. Por exemplo, consulte http://www.ss64.com/nt/set.html . Funcionará para CMD, não tenho certeza sobre arquivos .BAT

De um comentário a este post:

Esse link tem o comando " Set /P _MyVar=<MyFilename.txt" que diz que será definido _MyVarpara a primeira linha de MyFilename.txt. Isso pode ser usado como " myCmd > tmp.txt" com " set /P myVar=<tmp.txt". Mas ele só obterá a primeira linha da saída, nem toda a saída

Ilya Kochetov
fonte
2
Esse link possui o comando "Set / P _MyVar = <MyFilename.txt", que indica que ele definirá _MyVar para a primeira linha do MyFilename.txt. Isso pode ser usado como "myCmd> tmp.txt" com "set / P myVar = <tmp.txt". Mas ele só obterá a primeira linha da saída, nem toda a saída.
John Meagher
Esta resposta é para iniciantes como eu
5

Exemplo para definir na variável de ambiente "V" o arquivo mais recente

FOR /F %I IN ('DIR *.* /O:D /B') DO SET V=%I

em um arquivo em lotes, é necessário usar o prefixo duplo na variável de loop:

FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I
PabloG
fonte
2
Eu já vi essa abordagem antes, mas parece realmente hacky. Ele também tem o problema de capturar apenas a última linha de saída do comando na variável.
John Meagher
3

Basta usar o resultado do FORcomando. Por exemplo (dentro de um arquivo em lotes):

for /F "delims=" %%I in ('dir /b /a-d /od FILESA*') do (echo %%I)

Você pode usar %%Io valor que deseja. Assim como este: %%I.

E de antemão %%Inão possui espaços ou caracteres CR e pode ser usado para comparações !!

Raceableability
fonte
2

Se você está procurando a solução fornecida em Usando o resultado de um comando como argumento no bash?

então aqui está o código:

@echo off
if not "%1"=="" goto get_basename_pwd
for /f "delims=X" %%i in ('cd') do call %0 %%i
for /f "delims=X" %%i in ('dir /o:d /b') do echo %%i>>%filename%.txt
goto end

:get_basename_pwd
set filename=%~n1

:end
  • Isso se chamará com o resultado do comando CD, o mesmo que pwd.
  • A extração de string nos parâmetros retornará o nome do arquivo / pasta.
  • Obtenha o conteúdo desta pasta e acrescente ao nome do arquivo.txt

[Créditos] : Obrigado a todas as outras respostas e algumas pesquisas na página de comandos do Windows XP .

Gustavo Carreno
fonte
2
@echo off

ver | find "6.1." > nul
if %ERRORLEVEL% == 0 (
echo Win7
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)

ver | find "5.1." > nul
if %ERRORLEVEL% == 0 (
echo WinXP
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)
echo Outlook dir:  %findoutlook%
"%findoutlook%"
Caminhada
fonte
Obrigado por postar uma resposta! Enquanto um trecho de código poderia responder a pergunta ainda é grande para adicionar algumas informações adição ao redor, como explicar, etc ..
j0k
2

Gostaria de acrescentar um comentário às soluções acima:

Todas essas sintaxes funcionam perfeitamente bem se o seu comando for encontrado no caminho ou se o comando for um cmdpath SEM ESPAÇOS OU PERSONAGENS ESPECIAIS.

Mas, se você tentar usar um comando executável localizado em uma pasta cujo caminho contenha caracteres especiais, será necessário colocar o caminho do comando entre aspas duplas (") e a sintaxe FOR / F não funcionará.

Exemplos:

$ for /f "tokens=* USEBACKQ" %f in (
    `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" Hello '"F:\GLW7\Distrib\System\Shells and scripting"'`
) do echo %f
The filename, directory name, or volume label syntax is incorrect.

ou

$ for /f "tokens=* USEBACKQ" %f in (
      `"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'F:\GLW7\Distrib\System\Shells' is not recognized as an internal or external command, operable program or batch file.

ou

`$ for /f "tokens=* USEBACKQ" %f in (
     `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello' is not recognized as an internal or external command, operable program or batch file.

Nesse caso, a única solução que encontrei para usar um comando e armazenar seu resultado em uma variável é definir (temporariamente) o diretório padrão como o próprio comando:

pushd "%~d0%~p0"
FOR /F "tokens=* USEBACKQ" %%F IN (
    `FOLDERBROWSE "Hello world!" "F:\GLW7\Distrib\System\Layouts (print,display...)"`
) DO (SET MyFolder=%%F)
popd
echo My selected folder: %MyFolder%

O resultado está correto:

My selected folder: F:\GLW7\Distrib\System\OS install, recovery, VM\
Press any key to continue . . .

Obviamente, no exemplo acima, presumo que meu script em lote esteja localizado na mesma pasta que a do meu comando executável, para que eu possa usar a sintaxe "% ~ d0% ~ p0". Se esse não for o seu caso, você precisará encontrar uma maneira de localizar o caminho do comando e alterar o diretório padrão para o caminho.

NB: Para quem se pergunta, o exemplo de comando usado aqui (para selecionar uma pasta) é FOLDERBROWSE.EXE. Encontrei-o no site f2ko.de ( http://f2ko.de/en/cmd.php ).

Se alguém tiver uma solução melhor para esse tipo de comando acessível por um caminho complexo, ficarei muito feliz em ouvi-lo.

Gilles

Gilles Maisonneuve
fonte
Você pode prefixar seu comando com CALL. FOR / F não funciona se caminho tem espaços
jeb
@jeb: MUITO OBRIGADO! Agora meu código < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> funciona perfeitamente.
Gilles Maisonneuve
1

Você pode capturar toda a saída em uma variável, mas as linhas serão separadas por um caractere de sua escolha (# no exemplo abaixo) em vez de um CR-LF real.

@echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
)
echo directory contains:
echo %DIR%

Segunda versão, se você precisar imprimir o conteúdo linha por linha. Isso tira vantagem do fato de que não haverá linhas de saída duplicadas de "dir / b", portanto, pode não funcionar no caso geral.

@echo off
setlocal EnableDelayedExpansion
set count=0
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
    set /a count = !count! + 1
)

echo directory contains:
echo %DIR%

for /l %%c in (1,1,%count%) do (
    for /f "delims=#" %%i in ("!DIR!") do (
        echo %%i
        set DIR=!DIR:%%i=!
    )
)
Adam Mitz
fonte
0
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

o resultado é 'TXT: hola'

ivan rc
fonte
0

Você deve usar o forcomando, aqui está um exemplo:

@echo off
rem Commands go here
exit /b
:output
for /f "tokens=* useback" %%a in (`%~1`) do set "output=%%a"

e você pode usar, call :output "Command goes here"então a saída estará na %output%variável

Nota: Se você tiver uma saída de comando que é multilinha, esta ferramenta fará seta saída para a última linha do seu comando de multilinha.

Hayz
fonte
-1

Consulte este http://technet.microsoft.com/en-us/library/bb490982.aspx, que explica o que você pode fazer com a saída do comando.

Jack B Nimble
fonte
1
Esse artigo aborda apenas o redirecionamento e tópicos relacionados. Ele não responde à pergunta de como pegar a saída de um comando e colocá-la em uma variável.
John Meagher
3
Usando sua resposta, eu vim com isso: git pull>0 set /P RESULTVAR=<0 edit: Acho que não sei como usar quebras de linha aqui ... cada comando está em sua própria linha.
precisa