Come posso ottenere il risultato di un comando in una variabile in Windows?


132

Sto cercando di ottenere il risultato di un comando come variabile in uno script batch di Windows (vedere come ottenere il risultato di un comando in bash per l'equivalente scripting bash). È preferibile una soluzione che funzionerà in un file .bat, ma sono benvenute anche altre comuni soluzioni di scripting di Windows.


9
John, è ridicolmente difficile trovare questa domanda molto utile. Potresti considerare l'aggiunta di frasi alternative come Come acquisire l' output di un programma in una variabile in un file batch di Windows?
Piotr Dobrogost,

3
Google ha visualizzato questa pagina al 3 ° posto.
René Nyffenegger,

1
Un possibile duplicato del batch
Michael Freidgeim,

@MichaelFreidgeim questa domanda è stata effettivamente posta 2 anni prima di quel duplicato - ma ci sono più duplicati di questa domanda. Vedere i commenti su stackoverflow.com/questions/6359820/...
icc97

1
@ icc97, "Possibile duplicato" è un modo per ripulire - per chiudere domande simili e mantenerne una con le risposte migliori. La data non è essenziale. Vedi meta.stackexchange.com/questions/147643/… Se accetti che sia necessario un chiarimento, vota su meta.stackexchange.com/questions/281980/… Se vedi più duplicati, dovresti sceglierne uno come canonico e votare per chiuderne altri .
Michael Freidgeim,

Risposte:


34

Se devi catturare tutto l'output del comando puoi usare un batch come questo:

@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

Tutte le linee di uscita sono memorizzate in VAR separate da "!".

@John: c'è qualche utilità pratica per questo? Penso che dovresti guardare PowerShell o qualsiasi altro linguaggio di programmazione in grado di eseguire facilmente attività di scripting (Python, Perl, PHP, Ruby)


La risposta a riga singola risolverà il caso specifico che ho. Ho appena immaginato che esistesse un'opzione su più righe (o un'opzione su una riga più semplice). Immagino che le capacità dei file bat non siano proprio eccezionali. La necessità è per gli script bat che avvolgono le app Java. Costruire percorsi principalmente.
John Meagher,

Stai molto attento con quello. GWT ha anche provato a utilizzare i file batch per avviare Java con percorsi di classe specifici, il che è orribile non appena si arriva alle directory con caratteri non ASCII (in quel caso era la mia casa :)). Da allora l'hanno riscritto con VBS.
Joey,

25
c'è qualche uso pratico per questo? Stai scherzando? Questo è usato tutto il tempo in altre shell (tutte quelle GNU / Linux immagino) ed è molto utile.
Piotr Dobrogost,

1
@PiotrDobrogost Penso che quello che stava cercando di dire fosse che gli script bash sono un'orribile reliquia del passato (devi usare un ciclo for solo per catturare l'output di un programma? Seriamente?), E se mai arrivassi al punto dove ti trovi a dover usare le variabili, dovresti usare qualcosa di più moderno come PowerShell.
Ajedi32,

3
C'è un uso pratico, in realtà ... un po '. Voglio usare uno script di PowerShell per trovare un particolare percorso di Visual Studio, ma la cosa di cui ho bisogno al di fuori di quel percorso è un file batch che imposta un gruppo di variabili env in modo da poter chiamare editbin ... Quindi devo trovare il percorso e riportarlo all'istanza chiamante in cmdmodo da poterlo eseguire lì. ... Sì, è terribile quanto i suoni. Visual Studio mi fa venir voglia di piangere a volte. @ Ajedi32 Penso che intendevi dire che gli script batch sono una terribile reliquia del passato. ;)
jpmc26,

85

L'umile per il comando ha accumulato alcune funzionalità interessanti nel corso degli anni:

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

Si noti che "delims="sovrascrive lo spazio predefinito e i delimitatori di tab in modo che l'output del comando date venga inghiottito tutto in una volta.

Per catturare un output su più righe, può comunque essere essenzialmente un liner (usando la variabile lf come delimitatore nella variabile risultante):

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%

Per acquisire un'espressione convogliata, utilizzare ^|:

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

1
Come per la risposta di @ PabloG, questo funzionerà solo per ottenere l'ultima riga di output dal comando "date / t" in questo caso.
John Meagher,

11
Ho trovato la risposta al lavoro solo quando ho usato i segni di percentuale doppia, vale a direFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski

18
@Rabarberski: se digiti un forcomando direttamente sulla riga di comando, ne usi uno solo %. Se lo usi in un file batch, lo usi %%.
indiv

@tardate: Potresti dire come apparirà lo script, se è necessario passare l'argomento con il comando %, ad esempio:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k

1
@degenerate Il comando è valido a condizione che il datecomando utilizzato provenga da Cygwin. Sono d'accordo che avrei dovuto dirlo.
dma_k,

24

Per ottenere la directory corrente, è possibile utilizzare questo:

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

Sta usando un file temporaneo, quindi non è il più carino, ma sicuramente funziona! 'CD' inserisce la directory corrente in 'tmpFile', 'SET' carica il contenuto di tmpFile.

Ecco una soluzione per più righe con "array's":

@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

Ma potresti prendere in considerazione l'idea di passare a un'altra shell più potente o creare un'applicazione per questa roba. Sta allungando un po 'le possibilità dei file batch.


Esiste una variazione che funzionerà per acquisire più righe dal comando?
John Meagher,

6
Per ottenere la directory corrente puoi usare echo% CD%
Joe

9

devi usare il SETcomando con parametro /Pe indirizzare il tuo output su di esso. Ad esempio, consultare http://www.ss64.com/nt/set.html . Funzionerà con CMD, non sono sicuro dei file .BAT

Da un commento a questo post:

Quel link ha il comando " Set /P _MyVar=<MyFilename.txt" che dice che sarà impostato _MyVarsulla prima riga da MyFilename.txt. Questo potrebbe essere usato come " myCmd > tmp.txt" con " set /P myVar=<tmp.txt". Ma otterrà solo la prima riga dell'output, non tutto l'output


2
Quel link ha il comando "Set / P _MyVar = <MyFilename.txt" che dice che imposterà _MyVar sulla prima riga da MyFilename.txt. Questo potrebbe essere usato come "myCmd> tmp.txt" con "set / P myVar = <tmp.txt". Ma otterrà solo la prima riga dell'output, non tutto l'output.
John Meagher,

Questa risposta è per i principianti come me

5

Esempio per impostare nella variabile d'ambiente "V" il file più recente

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

in un file batch devi usare il doppio prefisso nella variabile loop:

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

2
Ho già visto questo approccio prima, ma sembra davvero confuso. Ha anche il problema che acquisirà solo l'ultima riga di output dal comando nella variabile.
John Meagher,

3

Usa semplicemente il risultato dal FORcomando. Ad esempio (all'interno di un file batch):

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

È possibile utilizzare %%Iil valore desiderato. Proprio come questo: %%I.

E in anticipo %%Inon ha spazi o caratteri CR e può essere utilizzato per i confronti !!


2

Se stai cercando la soluzione fornita in Usare il risultato di un comando come argomento in bash?

quindi ecco il codice:

@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
  • Questo si chiamerà con il risultato del comando CD, come pwd.
  • L'estrazione della stringa sui parametri restituirà il nome file / la cartella.
  • Ottieni il contenuto di questa cartella e aggiungi al nomefile.txt

[Crediti] : grazie a tutte le altre risposte e alcuni scavi sulla pagina dei comandi di Windows XP .


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

Grazie per aver inviato una risposta! Mentre uno snippet di codice potrebbe rispondere alla domanda, è comunque ottimo aggiungere alcune informazioni aggiuntive, come spiegare, ecc.
j0k

2

Vorrei aggiungere un'osservazione alle soluzioni di cui sopra:

Tutte queste sintassi funzionano perfettamente SE IL TUO COMANDO È TROVATO NEL PERCORSO o SE IL COMANDO È UN Cmdpath SENZA SPAZI O CARATTERI SPECIALI.

Ma se si tenta di utilizzare un comando eseguibile situato in una cartella il cui percorso contiene caratteri speciali, è necessario racchiudere il percorso del comando tra virgolette doppie (") e quindi la sintassi FOR / F non funziona.

Esempi:

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

o

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

o

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

In tal caso, l'unica soluzione che ho trovato per utilizzare un comando e memorizzare il suo risultato in una variabile è impostare (temporaneamente) la directory predefinita su quella del comando stesso:

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%

Il risultato è quindi corretto:

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

Ovviamente nell'esempio sopra, suppongo che il mio script batch si trovi nella stessa cartella di quello del mio comando eseguibile in modo da poter usare la sintassi "% ~ d0% ~ p0". Se questo non è il tuo caso, devi trovare un modo per individuare il tuo percorso di comando e cambiare la directory predefinita nel suo percorso.

NB: Per coloro che si chiedono, il comando di esempio utilizzato qui (per selezionare una cartella) è FOLDERBROWSE.EXE. L'ho trovato sul sito web f2ko.de ( http://f2ko.de/en/cmd.php ).

Se qualcuno ha una soluzione migliore per quel tipo di comandi accessibile attraverso un percorso complesso, sarò molto felice di sentirne parlare.

Gilles


È possibile aggiungere il prefisso al comando con CALL. FOR / F non funziona se il percorso ha spazi
jeb

@jeb: GRAZIE TANTO! Ora il mio codice < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> funziona perfettamente.
Gilles Maisonneuve,

1

Puoi catturare tutto l'output in una variabile, ma le linee saranno separate da un carattere di tua scelta (# nell'esempio sotto) invece di un CR-LF reale.

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

Seconda versione, se è necessario stampare i contenuti riga per riga. Ciò si avvantaggia del fatto che non ci saranno linee duplicate di output da "dir / b", quindi potrebbe non funzionare nel caso generale.

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

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

il risultato è 'TXT: hola'


0

Dovresti usare il forcomando, ecco un esempio:

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

e puoi usare call :output "Command goes here"quindi l'output sarà nella %output%variabile.

Nota: se si dispone di un output del comando setsu più righe , questo strumento eseguirà l'output sull'ultima riga del comando su più righe.


-1

Fare riferimento a questo http://technet.microsoft.com/en-us/library/bb490982.aspx che spiega cosa è possibile fare con l'output del comando.


1
L'articolo copre solo il reindirizzamento e argomenti correlati. Non risponde alla domanda su come prendere l'output di un comando e inserirlo in una variabile.
John Meagher,

3
Usando la sua risposta mi è venuto in mente questo: git pull>0 set /P RESULTVAR=<0 modifica: suppongo, non so come usare le interruzioni di riga qui ... ogni comando è sulla propria riga.
RibeiroBreno,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.