Wie erhalte ich das Ergebnis eines Befehls in einer Variablen in Windows?

132

Ich möchte das Ergebnis eines Befehls als Variable in einem Windows-Batch-Skript abrufen (siehe das Abrufen des Ergebnisses eines Befehls in bash für das Bash-Skriptäquivalent). Eine Lösung, die in einer .bat-Datei funktioniert, wird bevorzugt, aber auch andere gängige Windows-Skriptlösungen sind willkommen.

John Meagher
quelle
9
John, es ist lächerlich schwer, diese sehr nützliche Frage zu finden . Könnten Sie bitte eine alternative Formulierung hinzufügen, z. B. Wie wird die Ausgabe eines Programms in einer Variablen in einer Windows-Batchdatei erfasst ?
Piotr Dobrogost
3
Google hat diese Seite auf Platz 3 angezeigt.
René Nyffenegger
1
Mögliches Duplikat des Windows-Batches weist einer Variablen die Ausgabe eines Programms zu
Michael Freidgeim
@MichaelFreidgeim Diese Frage wurde tatsächlich 2 Jahre vor diesem Duplikat gestellt - aber es gibt mehrere Duplikate dieser Frage. Siehe die Kommentare auf stackoverflow.com/questions/6359820/…
icc97
1
@ icc97, "Mögliches Duplikat" ist eine Möglichkeit zur Bereinigung - um ähnliche Fragen zu schließen und eine mit den besten Antworten zu behalten. Das Datum ist nicht wesentlich. Siehe meta.stackexchange.com/questions/147643/…. Wenn Sie damit einverstanden sind, dass eine Klärung erforderlich ist, stimmen Sie bitte über meta.stackexchange.com/questions/281980/… ab. Wenn Sie mehrere Duplikate sehen, sollten Sie eines als kanonisch auswählen und abstimmen, um andere zu schließen .
Michael Freidgeim

Antworten:

34

Wenn Sie die gesamte Befehlsausgabe erfassen müssen, können Sie einen Stapel wie den folgenden verwenden:

@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

Alle Ausgangsleitungen werden in VAR gespeichert, getrennt durch "!".

@ John: Gibt es eine praktische Verwendung dafür? Ich denke, Sie sollten sich PowerShell oder eine andere Programmiersprache ansehen, mit der Skriptaufgaben problemlos ausgeführt werden können (Python, Perl, PHP, Ruby).

PabloG
quelle
Die einzeilige Antwort löst den speziellen Fall, den ich habe. Ich habe nur gedacht, dass es eine mehrzeilige Option gibt (oder eine einfachere einzeilige Option). Ich denke, die Fähigkeiten von Bat-Dateien sind einfach nicht so toll. Es werden Bat-Skripte benötigt, die Java-Apps umschließen. Hauptsächlich Klassenpfade bauen.
John Meagher
Sei sehr vorsichtig damit. GWT hat auch versucht, Batch-Dateien zum Starten von Java mit bestimmten Klassenpfaden zu verwenden, was schrecklich fehlgeschlagen ist, sobald Sie zu Verzeichnissen mit Nicht-ASCII-Zeichen gelangen (in diesem Fall war es mein Zuhause :)). Das haben sie seitdem mit VBS umgeschrieben.
Joey
25
Gibt es dafür einen praktischen Nutzen? Machst du Witze? Dies wird ständig in anderen Shells verwendet (alle GNU / Linux-Shells, denke ich) und ist sehr nützlich.
Piotr Dobrogost
1
@PiotrDobrogost Ich denke, was er damit sagen wollte, war, dass Bash-Skripte ein schreckliches Relikt der Vergangenheit sind (Sie müssen eine for-Schleife verwenden , um nur die Ausgabe eines Programms zu erfassen? Ernsthaft?), Und wenn Sie jemals auf den Punkt kommen Wenn Sie Variablen verwenden müssen, sollten Sie etwas Moderneres wie PowerShell verwenden.
Ajedi32
3
Es gibt eine praktische Verwendung, eigentlich ... irgendwie. Ich möchte ein PowerShell-Skript verwenden, um einen bestimmten Visual Studio-Pfad zu finden, aber das, was ich aus diesem Pfad heraus benötige, ist eine Batch-Datei, die eine Reihe von env-Variablen festlegt, damit ich editbin aufrufen kann ... Also muss ich den Pfad finden und bringe es zurück zur aufrufenden Instanz von, cmddamit ich es dort ausführen kann. ... Ja, das ist so schrecklich wie Geräusche. Visual Studio bringt mich manchmal zum Weinen. @ Ajedi32 Ich denke, Sie wollten damit sagen, dass Batch- Skripte ein schreckliches Relikt der Vergangenheit sind. ;)
jpmc26
85

Der demütige für Befehl hat einige interessante Fähigkeiten im Laufe der Jahre:

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

Beachten Sie, dass "delims="die Standardtrennzeichen für Leerzeichen und Tabulatoren überschrieben werden, sodass die Ausgabe des Datumsbefehls auf einmal verschlungen wird.

Um eine mehrzeilige Ausgabe zu erfassen, kann es sich im Wesentlichen immer noch um eine Einzeilerausgabe handeln (wobei die Variable lf als Begrenzer in der resultierenden Variablen verwendet wird):

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%

Verwenden Sie zum Erfassen eines Pipe-Ausdrucks ^|:

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
verspätet
quelle
1
Wie bei der Antwort von @ PabloG funktioniert dies nur, um die letzte Ausgabezeile des Befehls "Datum / t" in diesem Fall abzurufen.
John Meagher
11
Ich fand Ihre Antwort nur, wenn ich doppelte Prozentzeichen verwendete, dhFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski
18
@ Rabarberski: Wenn Sie einen forBefehl direkt in die Befehlszeile eingeben , verwenden Sie einen einzelnen %. Wenn Sie es in einer Batch-Datei verwenden, verwenden Sie %%.
indiv
@tardate: Könnten Sie bitte sagen, wie das Skript aussehen wird, wenn Befehl Befehl übergeben werden muss %, zum Beispiel:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k
1
@degenerate Der Befehl ist nur vorausgesetzt , daß dateBefehl kommt von Cygwin verwendet. Ich bin damit einverstanden, dass ich das hätte erwähnen sollen.
dma_k
24

Um das aktuelle Verzeichnis abzurufen, können Sie Folgendes verwenden:

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

Es wird zwar eine temporäre Datei verwendet, es ist also nicht die schönste, aber es funktioniert auf jeden Fall! 'CD' legt das aktuelle Verzeichnis in 'tmpFile' ab, 'SET' lädt den Inhalt von tmpFile.

Hier ist eine Lösung für mehrere Zeilen mit "Arrays":

@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

Möglicherweise möchten Sie jedoch zu einer anderen leistungsstärkeren Shell wechseln oder eine Anwendung für dieses Material erstellen. Es erweitert die Möglichkeiten der Batch-Dateien erheblich.

Böse Aktivität
quelle
Gibt es eine Variante, mit der mehrere Zeilen des Befehls erfasst werden können?
John Meagher
6
Um das aktuelle Verzeichnis zu erhalten, können Sie echo% CD%
Joe
9

Sie müssen den SETBefehl mit Parameter verwenden /Pund Ihre Ausgabe darauf richten. Siehe beispielsweise http://www.ss64.com/nt/set.html . Funktioniert für CMD, nicht sicher über .BAT-Dateien

Von einem Kommentar zu diesem Beitrag:

Dieser Link hat den Befehl " Set /P _MyVar=<MyFilename.txt", der besagt, dass er _MyVarin die erste Zeile von gesetzt wird MyFilename.txt. Dies könnte als " myCmd > tmp.txt" mit " set /P myVar=<tmp.txt" verwendet werden. Es wird jedoch nur die erste Zeile der Ausgabe angezeigt, nicht die gesamte Ausgabe

Ilya Kochetov
quelle
2
Dieser Link hat den Befehl "Set / P _MyVar = <MyFilename.txt", der besagt, dass _MyVar auf die erste Zeile von MyFilename.txt gesetzt wird. Dies könnte als "myCmd> tmp.txt" mit "set / P myVar = <tmp.txt" verwendet werden. Es wird jedoch nur die erste Zeile der Ausgabe angezeigt, nicht die gesamte Ausgabe.
John Meagher
Diese Antwort ist für Anfänger wie mich
5

Beispiel zum Festlegen der neuesten Datei in der Umgebungsvariablen "V"

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

In einer Batch-Datei müssen Sie das doppelte Präfix in der Schleifenvariablen verwenden:

FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I
PabloG
quelle
2
Ich habe diesen Ansatz schon einmal gesehen, aber er scheint wirklich hackig zu sein. Es hat auch das Problem, dass nur die letzte Ausgabezeile des Befehls in der Variablen erfasst wird.
John Meagher
3

Verwenden Sie einfach das Ergebnis aus dem FORBefehl. Zum Beispiel (innerhalb einer Batch-Datei):

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

Sie können das %%Ials den gewünschten Wert verwenden. Einfach so : %%I.

Und im Voraus hat der %%Ikeine Leerzeichen oder CR-Zeichen und kann für Vergleiche verwendet werden !!

Raceableability
quelle
2

Wenn Sie nach der Lösung suchen, die unter Verwenden des Ergebnisses eines Befehls als Argument in bash bereitgestellt wird ?

dann ist hier der 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
  • Dies ruft sich mit dem Ergebnis des CD-Befehls auf, genau wie pwd.
  • Die Zeichenfolgenextraktion für Parameter gibt den Dateinamen / Ordner zurück.
  • Holen Sie sich den Inhalt dieses Ordners und hängen Sie ihn an die Datei filename.txt an

[Credits] : Dank all der anderen Antworten und einigen Informationen auf der Windows XP-Befehlsseite .

Gustavo Carreno
quelle
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%"
Wanderung
quelle
Vielen Dank für die Beantwortung! Während ein Code-Snippet die Frage beantworten könnte, ist es immer noch großartig, einige zusätzliche Informationen hinzuzufügen, wie zum Beispiel erklären usw.
j0k
2

Ich möchte den obigen Lösungen eine Bemerkung hinzufügen:

Alle diese Syntaxen funktionieren einwandfrei, wenn Ihr Befehl im Pfad gefunden wurde oder wenn der Befehl ein Cmd-Pfad ohne Leerzeichen oder Sonderzeichen ist.

Wenn Sie jedoch versuchen, einen ausführbaren Befehl zu verwenden, der sich in einem Ordner befindet, dessen Pfad Sonderzeichen enthält, müssen Sie Ihren Befehlspfad in doppelte Anführungszeichen (") setzen, und die FOR / F-Syntax funktioniert dann nicht.

Beispiele:

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

oder

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

oder

`$ 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 diesem Fall besteht die einzige Lösung, die ich gefunden habe, um einen Befehl zu verwenden und sein Ergebnis in einer Variablen zu speichern, darin, das Standardverzeichnis (vorübergehend) auf das des Befehls selbst zu setzen:

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%

Das Ergebnis ist dann richtig:

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

Im obigen Beispiel gehe ich natürlich davon aus, dass sich mein Batch-Skript im selben Ordner befindet wie der meines ausführbaren Befehls, damit ich die Syntax "% ~ d0% ~ p0" verwenden kann. Wenn dies nicht der Fall ist, müssen Sie einen Weg finden, Ihren Befehlspfad zu finden und das Standardverzeichnis in seinen Pfad zu ändern.

NB: Für diejenigen, die sich fragen, lautet der hier verwendete Beispielbefehl (zum Auswählen eines Ordners) FOLDERBROWSE.EXE. Ich habe es auf der Website f2ko.de ( http://f2ko.de/en/cmd.php ) gefunden.

Wenn jemand eine bessere Lösung für diese Art von Befehlen hat, auf die über einen komplexen Pfad zugegriffen werden kann, würde ich mich sehr freuen, davon zu hören.

Gilles

Gilles Maisonneuve
quelle
Sie können Ihrem Befehl ein Präfix voranstellen CALL. FOR / F funktioniert nicht, wenn der Pfad Leerzeichen enthält
jeb
@jeb: VIELEN DANK! Jetzt CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"funktioniert mein Code < > perfekt.
Gilles Maisonneuve
1

Sie können alle Ausgaben in einer Variablen erfassen, die Zeilen werden jedoch durch ein Zeichen Ihrer Wahl (# im folgenden Beispiel) anstelle eines tatsächlichen CR-LF getrennt.

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

Zweite Version, wenn Sie den Inhalt zeilenweise ausdrucken müssen. Dies nutzt die Tatsache aus, dass es keine doppelten Ausgabezeilen von "dir / b" gibt, so dass es im allgemeinen Fall möglicherweise nicht funktioniert.

@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
quelle
0
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

das Ergebnis ist 'TXT: hola'

ivan rc
quelle
0

Sie sollten den forBefehl verwenden, hier ein Beispiel:

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

und Sie können verwenden, call :output "Command goes here"dann wird die Ausgabe in der %output%Variablen sein.

Hinweis: Wenn Sie eine mehrzeilige Befehlsausgabe haben, gibt dieses Tool setdie Ausgabe in die letzte Zeile Ihres mehrzeiligen Befehls aus.

Hayz
quelle
-1

Weitere Informationen hierzu finden Sie unter http://technet.microsoft.com/en-us/library/bb490982.aspx. Dort wird erläutert, was Sie mit der Befehlsausgabe tun können.

Jack B flink
quelle
1
Dieser Artikel behandelt nur die Weiterleitung und verwandte Themen. Es beantwortet nicht die Frage, wie die Ausgabe eines Befehls in eine Variable umgewandelt werden kann.
John Meagher
3
Mit seiner Antwort habe git pull>0 set /P RESULTVAR=<0 ich mir Folgendes ausgedacht : Bearbeiten: Ich glaube, ich weiß nicht, wie man Zeilenumbrüche hier verwendet ... jeder Befehl steht in einer eigenen Zeile.
RibeiroBreno