web-dev-qa-db-fra.com

Comment puis-je obtenir le résultat d'une commande dans une variable dans Windows?

Je cherche à obtenir le résultat d'une commande sous forme de variable dans un script batch Windows (voir comment obtenir le résultat d'une commande dans bash pour l'équivalent en script bash). Une solution qui fonctionnera dans un fichier .bat est préférable, mais d’autres solutions de script Windows courantes sont également les bienvenues. 

111
John Meagher

Si vous devez capturer toutes les sorties de commande, vous pouvez utiliser un lot comme celui-ci:

@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

Toutes les lignes de sortie sont stockées dans le VAR, séparées par "!".

@ John: y a-t-il une utilisation pratique pour cela? Je pense que vous devriez regarder PowerShell ou tout autre langage de programmation capable d'exécuter facilement des tâches de script (Python, Perl, PHP, Ruby).

29
PabloG

La commande humble pour a accumulé des capacités intéressantes au fil des ans:

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

Notez que "delims=" écrase les délimiteurs d'espace et de tabulation par défaut de sorte que la sortie de la commande date soit englobée en une seule fois.

Pour capturer une sortie multiligne, il peut toujours s'agir essentiellement d'une ligne (en utilisant la variable lf comme délimiteur dans la variable résultante):

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%

Pour capturer une expression acheminée, utilisez ^|:

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
75
tardate

Pour obtenir le répertoire actuel, vous pouvez utiliser ceci:

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

Il utilise un fichier temporaire, ce n’est donc pas le plus joli, mais ça marche! 'CD' met le répertoire actuel dans 'tmpFile', 'SET' charge le contenu de tmpFile.

Voici une solution pour plusieurs lignes avec "tableau":

@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

Mais vous voudrez peut-être envisager de passer à un autre shell plus puissant ou de créer une application pour ce genre de choses. Cela élargit un peu les possibilités des fichiers de commandes.

23
Evil Activity

vous devez utiliser la commande SET avec le paramètre /P et y diriger votre sortie . Par exemple, voir http://www.ss64.com/nt/set.html . Travaillera pour CMD, pas sûr des fichiers .BAT

D'un commentaire à ce post:

Ce lien a la commande "Set /P _MyVar=<MyFilename.txt" qui dit qu'il va définir _MyVar sur la première ligne à partir de MyFilename.txt. Cela pourrait être utilisé comme "myCmd > tmp.txt" avec "set /P myVar=<tmp.txt". Mais ce ne sera que obtenir la première ligne de la sortie, pas toute la sortie

7
Ilya Kochetov

Exemple pour définir dans la variable d’environnement "V" le fichier le plus récent 

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

dans un fichier batch, vous devez utiliser le préfixe double dans la variable de boucle:

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

Utilisez simplement le résultat de la commande FOR. Par exemple (dans un fichier de commandes):

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

Vous pouvez utiliser le %%I comme valeur souhaitée. Juste comme ceci: %%I.

Et à l’avance, le %%I ne contient ni espace ni caractère CR et peut être utilisé pour des comparaisons !!

3
Raceableability
@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%"
2
Hike

Si vous recherchez la solution fournie dans Vous utilisez le résultat d'une commande comme argument dans bash?

alors voici le code:

@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
  • Cela s’appellera avec le résultat de la commande CD, comme pwd.
  • L'extraction de chaîne sur les paramètres retournera le nom de fichier/dossier.
  • Récupère le contenu de ce dossier et l'ajoute au fichier filename.txt

[Credits]: Merci à toutes les autres réponses et quelques recherches sur les commandes Windows XP .

2
Gustavo Carreno

Vous pouvez capturer toutes les sorties dans une seule variable, mais les lignes seront séparées par un caractère de votre choix (# dans l'exemple ci-dessous) au lieu d'un CR-LF réel.

@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%

Deuxième version, si vous devez imprimer le contenu ligne par ligne. Cela tient compte du fait qu'il n'y aura pas de lignes de sortie en double de "dir/b", de sorte que cela peut ne pas fonctionner dans le cas général.

@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=!
    )
)
1
Adam Mitz

J'aimerais ajouter une remarque aux solutions ci-dessus:

Toutes ces syntaxes fonctionnent parfaitement si votre commande IS est trouvée dans le chemin ou si la commande IS un chemin de commande sans espaces OR caractères spéciaux.

Mais si vous essayez d'utiliser une commande exécutable située dans un dossier dont le chemin contient des caractères spéciaux, vous devrez alors inclure votre chemin de commande entre guillemets ("), puis la syntaxe FOR/F ne fonctionnera pas.

Exemples:

$ 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.

Dans ce cas, la seule solution que j'ai trouvée pour utiliser une commande et stocker son résultat dans une variable consiste à définir (temporairement) le répertoire par défaut sur celui de la commande elle-même:

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%

Le résultat est alors correct:

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

Bien entendu, dans l'exemple ci-dessus, je suppose que mon script de traitement par lots est situé dans le même dossier que celui de ma commande exécutable afin que je puisse utiliser la syntaxe "% ~ d0% ~ p0". Si ce n'est pas votre cas, vous devez trouver un moyen de localiser votre chemin de commande et de changer le répertoire par défaut en son chemin.

NB: Pour ceux qui s’interrogent, l’exemple de commande utilisé ici (pour sélectionner un dossier) est FOLDERBROWSE.EXE. Je l'ai trouvé sur le site Web f2ko.de ( http://f2ko.de/en/cmd.php ).

Si quelqu'un a une meilleure solution pour ce type de commandes accessible via un chemin complexe, je serai très heureux de l'entendre.

Gilles

1
Gilles Maisonneuve

Vous devriez utiliser la commande for, voici un exemple:

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

et vous pouvez utiliser call :output "Command goes here" alors la sortie sera dans la variable %output%.

Remarque: Si vous avez une sortie de commande multiligne, cet outil set affichera la sortie à la dernière ligne de votre commande multiligne.

0
Hayz
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

le résultat est 'TXT: hola'

0
ivan rc