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

132

Je cherche à obtenir le résultat d'une commande en tant que variable dans un script batch Windows (voir comment obtenir le résultat d'une commande en bash pour l'équivalent du 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.

John Meagher
la source
9
John, il est ridiculement difficile de trouver cette question très utile. Pourriez-vous s'il vous plaît envisager d'ajouter une formulation alternative comme Comment capturer la sortie d'un programme dans une variable dans un fichier de commandes Windows?
Piotr Dobrogost
3
Google a affiché cette page au 3e rang.
René Nyffenegger
1
Possible duplication du lot Windows assigner la sortie d'un programme à une variable
Michael Freidgeim
@MichaelFreidgeim, cette question a été posée 2 ans avant ce doublon - mais il y a plusieurs doublons de cette question. Voir les commentaires sur stackoverflow.com/questions/6359820/…
icc97
1
@ icc97, "Possible duplicate" est un moyen de nettoyer - pour fermer des questions similaires et en garder une avec les meilleures réponses. La date n'est pas indispensable. Voir meta.stackexchange.com/questions/147643/ ... Si vous acceptez que cela nécessite des éclaircissements, veuillez voter sur meta.stackexchange.com/questions/281980/… Si vous voyez plusieurs doublons, vous devriez en choisir un comme canonique et voter pour en fermer les autres .
Michael Freidgeim

Réponses:

34

Si vous devez capturer toute la sortie de la 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 VAR séparées par "!".

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

PabloG
la source
La réponse sur une seule ligne résoudra le cas spécifique que j'ai. J'ai juste pensé qu'il y avait une option multiligne (ou une option simple ligne plus simple). Je suppose que les capacités des fichiers bat ne sont tout simplement pas géniales. Le besoin en est que les scripts bat encapsulent les applications Java. Construire principalement des classpaths.
John Meagher
Soyez très prudent avec cela. GWT a également essayé d'utiliser des fichiers batch pour démarrer Java avec des chemins de classe spécifiques, ce qui a échoué horriblement dès que vous arrivez dans des répertoires avec des caractères non ASCII (dans ce cas, c'était chez moi :)). Ils ont depuis réécrit cela avec VBS.
Joey
25
y a-t-il une utilité pratique pour cela? Est-ce que vous plaisantez? Ceci est utilisé tout le temps dans d'autres shells (tous ceux GNU / Linux je suppose) et c'est très utile.
Piotr Dobrogost
1
@PiotrDobrogost Je pense que ce qu'il essayait de dire, c'est que les scripts bash sont une horrible relique du passé (vous devez utiliser une boucle for juste pour capturer la sortie d'un programme? Sérieusement?), Et si jamais vous en venez au fait là où vous devez utiliser des variables, vous devez utiliser quelque chose de plus moderne comme PowerShell.
Ajedi32
3
Il y a une utilisation pratique, en fait ... un peu. Je veux utiliser un script PowerShell pour trouver un chemin Visual Studio particulier, mais la chose dont j'ai besoin hors de ce chemin est un fichier batch qui définit un tas de variables d'environnement afin que je puisse appeler editbin ... Je dois donc trouver le chemin et le renvoyer vers l'instance appelante de cmdpour que je puisse l'exécuter là-bas. ... Oui, c'est aussi terrible que des sons. Visual Studio me donne parfois envie de pleurer. @ Ajedi32 Je pense que vous vouliez dire que les scripts batch sont une horrible relique du passé. ;)
jpmc26
85

L'humble du commandement 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="remplace l'espace par défaut et les délimiteurs de tabulation afin que la sortie de la commande de date soit engloutie en une seule fois.

Pour capturer la sortie multiligne, il peut encore s'agir essentiellement d'une ligne unique (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 canalisée, utilisez ^|:

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
tarder
la source
1
Comme pour la réponse de @ PabloG, cela ne fonctionnera que pour obtenir la dernière ligne de sortie de la commande, "date / t" dans ce cas.
John Meagher
11
J'ai trouvé votre réponse efficace uniquement lorsque j'ai utilisé des signes à double pourcentage, c'estFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski
18
@Rabarberski: Si vous tapez une forcommande directement sur la ligne de commande, vous en utilisez un %. Si vous l'utilisez dans un fichier de commandes, vous utilisez %%.
indiv du
@tardate: Pourriez-vous s'il vous plaît dire à quoi ressemblera le script, si la commande doit être passée en argument avec %, par exemple:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k
1
@degenerate La commande est valide à condition que la datecommande utilisée provienne de Cygwin. Je conviens que j'aurais dû le mentionner.
dma_k
24

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, donc ce n'est pas le plus joli, mais cela fonctionne certainement! 'CD' place le répertoire courant dans 'tmpFile', 'SET' charge le contenu de tmpFile.

Voici une solution pour plusieurs lignes avec des "tableaux":

@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 étend un peu les possibilités des fichiers batch.

Activité maléfique
la source
Existe-t-il une variante qui fonctionnera pour capturer plusieurs lignes à partir de la commande?
John Meagher
6
Pour obtenir le répertoire courant, vous pouvez utiliser echo% CD%
Joe
9

vous devez utiliser la SETcommande avec le paramètre /Pet y diriger votre sortie. Par exemple, consultez http://www.ss64.com/nt/set.html . Fonctionnera pour CMD, pas sûr des fichiers .BAT

D'un commentaire à ce post:

Ce lien a la commande " Set /P _MyVar=<MyFilename.txt" qui indique qu'il sera défini _MyVarsur la première ligne à partir de MyFilename.txt. Cela pourrait être utilisé comme " myCmd > tmp.txt" avec " set /P myVar=<tmp.txt". Mais il n'obtiendra que la première ligne de la sortie, pas toute la sortie

Ilya Kochetov
la source
2
Ce lien a la commande "Set / P _MyVar = <MyFilename.txt" qui indique qu'il définira _MyVar sur la première ligne de MyFilename.txt. Cela pourrait être utilisé comme "myCmd> tmp.txt" avec "set / P myVar = <tmp.txt". Mais il n'obtiendra que la première ligne de la sortie, pas toute la sortie.
John Meagher
Cette réponse est pour les débutants comme moi
5

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 double préfixe dans la variable de boucle:

FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I
PabloG
la source
2
J'ai déjà vu cette approche, mais cela semble vraiment piraté. Il a également le problème qu'il ne capturera que la dernière ligne de sortie de la commande dans la variable.
John Meagher
3

Utilisez simplement le résultat de la FORcommande. Par exemple (dans un fichier batch):

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

Vous pouvez utiliser la %%Icomme valeur souhaitée. Tout comme ceci: %%I.

Et à l'avance, le %%In'a pas d'espaces ou de caractères CR et peut être utilisé pour des comparaisons !!

Raceableability
la source
2

Si vous recherchez la solution fournie dans Utilisation du 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
  • Celui-ci s'appellera avec le résultat de la commande CD, identique à pwd.
  • L'extraction de chaîne sur les paramètres renverra le nom de fichier / dossier.
  • Récupérez le contenu de ce dossier et ajoutez-le au nom de fichier.txt

[Crédits] : Merci à toutes les autres réponses et quelques recherches sur la page des commandes de Windows XP .

Gustavo Carreno
la source
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%"
Une randonnée
la source
Merci d'avoir publié une réponse! Bien qu'un extrait de code puisse répondre à la question, il est toujours bon d'ajouter des informations supplémentaires, comme expliquer, etc.
j0k
2

Je voudrais ajouter une remarque aux solutions ci-dessus:

Toutes ces syntaxes fonctionnent parfaitement bien SI VOTRE COMMANDE EST TROUVÉE DANS LE CHEMIN ou SI LA COMMANDE EST UN cmdpath SANS ESPACES OU 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 devez placer votre chemin de commande entre guillemets doubles (") et la syntaxe FOR / F ne fonctionne 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 est de 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 sûr, dans l'exemple ci-dessus, je suppose que mon script batch 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 remplacer le répertoire par défaut par 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 d'en entendre parler.

Gilles

Gilles Maisonneuve
la source
Vous pouvez préfixer votre commande avec CALL. FOR / F ne fonctionne pas si le chemin contient des espaces
jeb
@jeb: MERCI BEAUCOUP! Maintenant, mon code < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> fonctionne parfaitement.
Gilles Maisonneuve
1

Vous pouvez capturer toute la sortie dans une 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 prend avantage du fait qu'il n'y aura pas de lignes dupliquées de sortie de "dir / b", donc 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=!
    )
)
Adam Mitz
la source
0
@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'

ivan rc
la source
0

Vous devez utiliser la forcommande, 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 %output%variable.

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

Hayz
la source
-1

Veuillez vous référer à ce http://technet.microsoft.com/en-us/library/bb490982.aspx qui explique ce que vous pouvez faire avec la sortie de commande.

Jack B Nimble
la source
1
Cet article ne couvre que la redirection et les sujets connexes. Cela ne répond pas à la question de savoir comment prendre la sortie d'une commande et la placer dans une variable.
John Meagher
3
En utilisant sa réponse, j'ai trouvé ceci: git pull>0 set /P RESULTVAR=<0 modifier: Je suppose, je ne sais pas comment utiliser les sauts de ligne ici ... chaque commande est sur sa propre ligne.
RibeiroBreno