Як отримати результат команди в змінній у Windows?


132

Я хочу отримати результат команди як змінної в пакетному сценарії Windows (дивіться, як отримати результат команди в bash для еквівалента сценарію bash). Бажано рішення, яке працюватиме у файлі .bat, але також вітаються інші поширені рішення сценаріїв Windows.


9
Джон, смішно важко знайти це дуже корисне питання. Чи не могли б ви розглянути питання про додавання альтернативного фразування , як Як захопити на виході з аа програми в змінну в пакетному файлі з Windows?
Пьотр Доброгост

3
Google відобразила цю сторінку на 3-му місці.
Рене Ніффенеггер


@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 просто не такі великі. Потреба в цьому полягає в сценаріях bat, що обгортають програми Java. В основному будують класоводи.
Джон Мізер

Будьте дуже обережні з цим. GWT також намагався використовувати пакетні файли для запуску Java з певними класовими шляхами, що жахливо вийшло, як тільки ви потрапили в каталоги з символами, що не належать до ASCII (у такому випадку це був мій дім :)). Вони з тих пір переписали це з VBS.
Joey

25
чи є для цього практичне використання? Ви жартуєте? Це використовується постійно в інших оболонках (я думаю, всі GNU / Linux), і це дуже корисно.
Пьотр Доброгост

1
@PiotrDobrogost Я думаю, що він намагався сказати, що скрипти bash - це жахливий пережиток минулого (Вам потрібно скористатись циклом просто для того, щоб зафіксувати вихід програми? Серйозно?), І якщо ви коли-небудь доберетесь до справи там, де вам знадобиться використовувати змінні, вам слід використовувати щось більш сучасне, як PowerShell.
Ajedi32

3
Існує практичне використання, насправді ... свого роду. Я хочу використовувати скрипт PowerShell, щоб знайти конкретний шлях Visual Studio, але мені потрібна річ із цього шляху - пакетний файл, який встановлює купу env vars, щоб я міг викликати 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="перезаписується простір та роздільники вкладки, щоб результат команди дата одразу збився.

Для отримання багаторядкового виводу він все ще може бути однолінійним (використовуючи змінну 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
Рабарберскі,

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%

Хоча він використовує temp-файл, тому він не самий гарний, але він, безумовно, працює! '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.
  • Вилучення рядків за параметрами поверне ім'я файлу / папки.
  • Отримайте вміст цієї папки та додайте до імені файлу.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

Я хотів би додати зауваження до вищезазначених рішень:

Усі ці синтаксиси чудово працюють, ЯКЩО ВАША КОМАНДА ЗНАЙДАЄТЬСЯ ВІД ПАРТИ, АКОЛЬ КОМАНДА - це шлях без БЕЗ ПРОСТОРІВ І СПЕЦІАЛЬНИХ ХАРАКТЕРІВ.

Але якщо ви спробуєте скористатися виконуваною командою, розташованою в папці, шлях якої містить спеціальні символи, то вам потрібно буде скласти ваш командний шлях у подвійні лапки ("), і тоді синтаксис 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". Якщо це не ваш випадок, то вам доведеться знайти спосіб знайти ваш командний шлях та змінити каталог за замовчуванням на його шлях.

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

Якщо у когось є краще рішення для таких команд, доступних через складний шлях, я буду дуже радий почути це.

Жиль


Ви можете префіксувати свою команду за допомогою CALL. FOR / F не працює, якщо на шляху є пробіли
jeb

@jeb: ДЯКУЄТЕ ТАКІ МНОГО! Тепер мій код < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> працює чудово.
Жил Мейсонн

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.