Attribuer la sortie d'un programme à une variable à l'aide d'un fichier batch MS

290

J'ai besoin d'assigner la sortie d'un programme à une variable à l'aide d'un fichier batch MS.

Donc, dans le shell GNU Bash, j'utiliserais VAR=$(application arg0 arg1). J'ai besoin d'un comportement similaire dans Windows en utilisant un fichier batch.

Quelque chose comme set VAR=application arg0 arg1.

initialZero
la source

Réponses:

433

Une façon est:

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

Un autre est:

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

Notez que la première %entrée %%iest utilisée pour échapper à la %suite et est nécessaire lors de l'utilisation du code ci-dessus dans un fichier de commandes plutôt que sur la ligne de commande. Imaginez, votre test.bata quelque chose comme:

for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%
Carlos Gutiérrez
la source
11
C'est une super astuce, je me demande pourquoi ça ne marche pas avec une pipe
Bill K
25
Cela ne fonctionne que pour la sortie qui est une seule ligne de texte (les lignes suivantes sont omises après le premier saut de ligne).
GroovyCakes
20
@Machta le tuyau doit être échappé avec un signe ^ devant lui, à l'intérieur de l'expression en parens. Exemple:for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"
Emanuele Del Grande
8
Ne travaillez pas pour la ligne avec les espaces. Par exemple: pour / f %% i dans ('ver'), définissez VAR = %% i. Comme écrit @Renat, devrait ajouter "tokens = *"
Yura Shinkarev
2
@GroovyCakes Votre question sur plusieurs lignes dans la sortie est répondue par cette réponse sur une question en double
icc97
67

En plus de cette réponse précédente , les tuyaux peuvent être utilisés dans une instruction for, échappés par un symbole caret:

    for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i
Renat
la source
1
Deux points importants: utilisez des jetons pour capturer et un curseur pour échapper au tuyau.
Christopher Oezbek
6
Version équivalente qui fonctionne sur la CLI et qui peut être copiée-collée pour faciliter le bricolage: for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %imais en général, le usebackqdevrait être utilisé pour gérer des commandes complexes.
Amit Naidu
Des jetons étaient nécessaires pour gérer les espaces dans la sortie.
Mark Ingram
Citations fonctionnent aussi bien pour moi, comme ceci: for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i. Plus facile pour moi s'il n'y a pas de guillemets dans la commande elle-même.
Paul
10

@OP, vous pouvez utiliser des boucles for pour capturer l'état de retour de votre programme, s'il génère autre chose que des nombres

ghostdog74
la source
8

en supposant que la sortie de votre application est un code de retour numérique, vous pouvez effectuer les opérations suivantes

application arg0 arg1
set VAR=%errorlevel%
akf
la source
5
Malheureusement, la sortie est une chaîne.
initialZero
D'accord. je garderai cela pour la postérité, mais jetez un oeil au lien de @ jdigital, qui parle de la sortie de la tuyauterie dans un fichier temporaire.
akf
1
La sortie du programme vers stdout et stderr est différente de sa valeur de retour entière. Un programme peut à la fois retourner une valeur entière comme dans l'exemple ci-dessus, tout en envoyant une chaîne à la console (ou redirigé vers un fichier ou ailleurs). Ils ne s'excluent pas mutuellement et sont deux concepts différents.
David Rector
7

Lors de l'exécution: for /f %%i in ('application arg0 arg1') do set VAR=%%ij'obtenais une erreur: %% j'étais inattendu à ce moment. Comme correctif, j'ai dû exécuter ci-dessus commefor /f %i in ('application arg0 arg1') do set VAR=%i

Munish Mehta
la source
9
Dans un fichier batch dont vous avez besoin %%et en dehors d'un fichier batch sur une ligne de commande dont vous avez besoin%
Jerry Jeremiah
2

En plus de la réponse, vous ne pouvez pas utiliser directement les opérateurs de redirection de sortie dans la partie définie de la forboucle (par exemple, si vous souhaitez masquer la sortie stderror d'un utilisateur et fournir un message d'erreur plus agréable). Au lieu de cela, vous devez leur échapper avec un caractère caret ( ^):

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

Référence: rediriger la sortie de la commande dans la boucle du script de commandes

Kubo2
la source
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
la source
(plus1) pour l'explication des backticks
Sandburg
1

Vous pouvez utiliser une macro batch pour une capture simple des sorties de commande, un peu comme le comportement du shell bash.

L'utilisation de la macro est simple et ressemble à

%$set% VAR=application arg1 arg2

Et cela fonctionne même avec des tuyaux

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

La macro utilise la variable comme un tableau et stocke chaque ligne dans un index séparé.
Dans l'exemple de %$set% allDrives="wmic logicaldisk, les variables suivantes seront créées:

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>

Pour l'utiliser, il n'est pas important de comprendre comment fonctionne la macro elle-même.

L'exemple complet

@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
la source
0

J'ai écrit le script qui interroge google.com toutes les 5 secondes et enregistre les résultats avec l'heure actuelle. Ici vous pouvez trouver la sortie des variables "commandLineStr" (avec index)

@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
la source