Как получить результат выполнения команды в переменной в Windows?


133

Я хочу получить результат команды в виде переменной в пакетном сценарии Windows (см., Как получить результат команды в bash для эквивалента сценария bash). Решение, которое будет работать с файлом .bat, является предпочтительным, но также приветствуются другие распространенные решения сценариев Windows.


10
Джон, найти этот очень полезный вопрос до смешного сложно . Не могли бы вы рассмотреть вопрос о добавлении альтернативного фразировки , как Как захватить на выходе из аа программы в переменную в пакетном файле с Windows?
— Петр Доброгост

3
Google показал эту страницу на 3-м месте.
— Рене Ниффенеггер, 06

1
Возможный дубликат пакетной
— Майкл

@MichaelFreidgeim, этот вопрос был задан за 2 года до этого дубликата, но есть несколько дубликатов этого вопроса. См. Комментарии на stackoverflow.com/questions/6359820/…
— icc97

1
@ icc97, «Возможный дубликат» - это способ очистки - закрыть похожие вопросы и оставить один с лучшими ответами. Дата не важна. См. Meta.stackexchange.com/questions/147643/… Если вы согласны с тем, что это требует разъяснения, пожалуйста, проголосуйте на meta.stackexchange.com/questions/281980/… Если вы видите несколько дубликатов, вы должны выбрать один как канонический и проголосовать за закрытие других ,
— Майкл

Ответы:


34

Если вам нужно захватить весь вывод команды, вы можете использовать такой пакет:

@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

Все выходные строки сохраняются в VAR, разделенные знаком "!".

@John: есть ли в этом практическая польза? Я думаю, вам стоит посмотреть PowerShell или любой другой язык программирования, способный легко выполнять скриптовые задачи (Python, Perl, PHP, Ruby).


Ответ в одну строку решит конкретный случай, который у меня есть. Я просто подумал, что есть вариант с несколькими строками (или более простой вариант с одной строкой). Я думаю, возможности файлов bat не так уж велики. Это необходимо для сценариев летучих мышей, обертывающих приложения Java. В основном создание путей к классам.
— Джон Мигер,

Будьте с этим очень осторожны. GWT также пытался использовать командные файлы для запуска Java с определенными путями к классам, что ужасно провалилось, как только вы попали в каталоги с символами, отличными от ASCII (в этом случае это был мой дом :)). С тех пор они переписали это с помощью VBS.
— Joey

26
есть ли в этом практическая польза? Ты смеешься? Это постоянно используется в других оболочках (думаю, во всех оболочках GNU / Linux), и это очень полезно.
— Петр Доброгост,

2
@PiotrDobrogost Я думаю, что он пытался сказать, что сценарии bash - это ужасный пережиток прошлого (вам нужно использовать цикл for только для захвата вывода программы? Серьезно?), И если вы когда-нибудь дойдете до сути там, где вам нужно использовать переменные, вам следует использовать что-то более современное, например PowerShell.
— Ajedi32

3
Практическое применение, собственно, есть ... вроде как. Я хочу использовать сценарий PowerShell, чтобы найти конкретный путь к Visual Studio, но то, что мне нужно из этого пути, - это пакетный файл, который устанавливает кучу переменных env, поэтому я могу вызвать editbin ... Итак, мне нужно найти путь и вернуть его вызывающему экземпляру, cmdчтобы я мог запустить его там. ... Да, это ужасно, как звучит. Visual Studio иногда заставляет меня плакать. @ Ajedi32 Я думаю, вы хотели сказать, что пакетные скрипты - это ужасный пережиток прошлого. ;)
— jpmc26

85

Скромный командир за годы накопил несколько интересных способностей:

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

Обратите внимание, что "delims="перезаписываются разделители пробелов и табуляции по умолчанию, так что вывод команды date сразу же проглатывается.

Для захвата многострочного вывода он все еще может быть однострочным (с использованием переменной lf в качестве разделителя в результирующей переменной):

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%

Чтобы записать конвейерное выражение, используйте ^|:

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

1
Как и в случае с ответом @PabloG, это будет работать только для получения последней строки вывода команды, в данном случае «date / t».
— Джон Мигер,

11
Я обнаружил, что ваш ответ работает только тогда, когда я использовал двойные знаки процента, то естьFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
— Rabarberski

18
@Rabarberski: Если вы вводите forкоманду прямо в командной строке, вы используете одиночный %. Если вы используете его в пакетном файле, вы используете %%.
— indiv

@tardate: Не могли бы вы рассказать, как будет выглядеть скрипт, если команде нужно передать аргумент %, например:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
— dma_k

1
@degenerate Команда действительна при условии, что dateиспользуемая команда исходит от Cygwin. Я согласен, я должен был упомянуть об этом.
— dma_k

24

Чтобы получить текущий каталог, вы можете использовать это:

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

Хотя он использует временный файл, поэтому он не самый красивый, но, безусловно, работает! «CD» помещает текущий каталог в «tmpFile», «SET» загружает содержимое tmpFile.

Вот решение для нескольких строк с "массивом":

@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

Но вы можете подумать о переходе на другую, более мощную оболочку или создать приложение для этого. Это немного расширяет возможности командных файлов.


Есть ли вариант, который будет работать для захвата нескольких строк из команды?
— Джон Мигер,

6
Чтобы получить текущий каталог, вы можете использовать echo% CD%
— Джо,

9

вам нужно использовать SETкоманду с параметром /Pи направить на него свой вывод. Например, см. Http://www.ss64.com/nt/set.html . Будет работать для CMD, не уверен в файлах .BAT

Из комментария к этому сообщению:

У этой ссылки есть команда " Set /P _MyVar=<MyFilename.txt", которая говорит, что она будет установлена _MyVarна первую строку из MyFilename.txt. Это может быть использовано как myCmd > tmp.txt«с set /P myVar=<tmp.txt». Но он получит только первую строку вывода, а не весь вывод


2
В этой ссылке есть команда «Set / P _MyVar = <MyFilename.txt», которая говорит, что она установит _MyVar на первую строку из MyFilename.txt. Его можно использовать как «myCmd> tmp.txt» с «set / P myVar = <tmp.txt». Но он получит только первую строку вывода, а не весь вывод.
— Джон Мигер,

Этот ответ предназначен для таких начинающих, как я

5

Пример установки в переменной среды "V" самого последнего файла

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

в пакетном файле вы должны использовать двойной префикс в переменной цикла:

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

2
Я видел этот подход раньше, но он кажется действительно хакерским. У него также есть проблема, заключающаяся в том, что он захватывает только последнюю строку вывода команды в переменной.
— Джон Мигер,

3

Просто используйте результат FORкоманды. Например (внутри командного файла):

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

Вы можете использовать в %%Iкачестве желаемого значения. Так же , как это: %%I.

И заранее %%Iне имеет пробелов или символов CR и может использоваться для сравнения !!


2

Если вы ищете решение, представленное в разделе Использование результата команды в качестве аргумента в bash?

тогда вот код:

@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
  • Это вызовет себя с результатом команды CD, так же, как pwd.
  • Извлечение строки по параметрам вернет имя файла / папку.
  • Получите содержимое этой папки и добавьте в filename.txt

[Кредиты] : Спасибо всем остальным ответам и некоторым копаниям на странице команд 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%"

Спасибо за ответ! Хотя фрагмент кода может ответить на этот вопрос, все же здорово добавить дополнительную информацию, например, объяснить и т. Д.
— j0k

2

К приведенным выше решениям я хотел бы добавить замечание:

Все эти синтаксисы работают отлично, ЕСЛИ ВАША КОМАНДА НАЙДЕНА В ПУТИ или ЕСЛИ КОМАНДА ЯВЛЯЕТСЯ cmdpath БЕЗ ПРОБЕЛОВ ИЛИ СПЕЦИАЛЬНЫХ СИМВОЛОВ.

Но если вы попытаетесь использовать исполняемую команду, расположенную в папке, путь которой содержит специальные символы, вам нужно будет заключить путь к вашей команде в двойные кавычки ("), и тогда синтаксис FOR / F не будет работать.

Примеры:

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

или

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

или

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

В этом случае единственное решение, которое я нашел для использования команды и сохранения ее результата в переменной, - это установить (временно) каталог по умолчанию для самой команды:

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%

Тогда результат правильный:

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

Конечно, в приведенном выше примере я предполагаю, что мой пакетный сценарий находится в той же папке, что и одна из моих исполняемых команд, так что я могу использовать синтаксис «% ~ d0% ~ p0». Если это не ваш случай, вам нужно найти способ найти путь к вашей команде и изменить каталог по умолчанию на его путь.

NB: Для тех, кому интересно, здесь используется пример команды (для выбора папки) FOLDERBROWSE.EXE. Я нашел его на сайте f2ko.de ( http://f2ko.de/en/cmd.php ).

Если у кого-то есть лучшее решение для таких команд, доступных через сложный путь, я буду очень рад услышать об этом.

жилль


Вы можете префикс своей команды с помощью CALL. FOR / F не работает, если в пути есть пробелы
— jeb

@jeb: БОЛЬШОЕ СПАСИБО! Теперь мой код < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> отлично работает.
— Gilles Maisonneuve

1

Вы можете записать весь вывод в одну переменную, но строки будут разделены выбранным вами символом (# в примере ниже) вместо фактического CR-LF.

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

Вторая версия, если вам нужно распечатать содержимое построчно. При этом учитывается тот факт, что не будет повторяющихся строк вывода из "dir / b", поэтому в общем случае это может не работать.

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

результат - "TXT: hola"


0

Вам следует использовать forкоманду, вот пример:

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

и вы можете использовать, call :output "Command goes here"тогда вывод будет в %output%переменной.

Примечание. Если у вас есть многострочный вывод команды, этот инструмент будет setвыводить его в последнюю строку многострочной команды.


-1

См. Http://technet.microsoft.com/en-us/library/bb490982.aspx, где объясняется, что вы можете делать с выводом команд.


1
Эта статья касается только перенаправления и связанных тем. Он не отвечает на вопрос, как получить результат одной команды и преобразовать его в переменную.
— Джон Мигер,

3
Используя его ответ, я придумал следующее: git pull>0 set /P RESULTVAR=<0 edit: Думаю, я не знаю, как использовать здесь разрывы строк ... каждая команда находится в отдельной строке.
— RibeiroBreno
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.