Windows'ta bir değişkendeki bir komutun sonucunu nasıl alırım?


132

Bir komutun sonucunu bir Windows toplu iş komut dosyasında değişken olarak elde etmeye çalışıyorum ( bash komut dosyası eşdeğeri için bash'deki bir komutun sonucunu nasıl elde edeceğinizi öğrenin ). Bir .bat dosyasında çalışacak bir çözüm tercih edilir, ancak diğer yaygın Windows komut dosyası çözümleri de memnuniyetle karşılanır.


9
John, bu çok yararlı soruyu bulmak gülünç derecede zor . Eğer gibi alternatif cümlelenmesini eklemeyi düşünün lütfen Could Nasıl yakalamak çıkışını aa ait programına Windows toplu iş dosyasında bir değişken içine?
Piotr Dobrogost

3
Google bu sayfayı 3. sırada görüntüledi.
René Nyffenegger


@MichaelFreidgeim'e bu soru aslında bu kopyadan 2 yıl önce sorulmuştu - ancak bu sorunun birden fazla kopyası var. Stackoverflow.com/questions/6359820/…
icc97

1
@ icc97, "Olası yineleme", benzer soruları kapatmak ve en iyi yanıtları içeren birini tutmak için bir temizlik yöntemidir. Tarih önemli değildir. Bkz. Meta.stackexchange.com/questions/147643/… Eğer açıklama gerektirdiğini kabul ediyorsanız, lütfen meta.stackexchange.com/questions/281980/… ' e oy verin Birden fazla kopya görürseniz, birini standart olarak seçmeli ve diğerlerini kapatmak için oylamalısınız .
Michael Freidgeim

Yanıtlar:


34

Tüm komut çıktısını yakalamanız gerekiyorsa, bunun gibi bir toplu iş kullanabilirsiniz:

@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

Tüm çıkış hatları "!" İle ayrılmış VAR'da saklanır.

@John: Bunun pratik bir kullanımı var mı? PowerShell'i veya komut dosyası oluşturma görevlerini kolayca gerçekleştirebilecek başka bir programlama dilini (Python, Perl, PHP, Ruby) izlemeniz gerektiğini düşünüyorum.


Tek satırlık cevap, sahip olduğum özel durumu çözecektir. Çok hatlı bir seçenek (veya daha kolay tek hat seçeneği) olduğunu düşündüm. Sanırım yarasa dosyalarının yetenekleri o kadar da harika değil. Bunun ihtiyacı, Java uygulamalarını saran yarasa betikleri içindir. Esas olarak sınıf yolları inşa etmek.
John Meagher

Buna çok dikkat et. GWT ayrıca Java'yı belirli sınıf yollarıyla başlatmak için toplu iş dosyalarını kullanmayı denedi; bu, ASCII olmayan karakterler içeren dizinlere ulaşır ulaşmaz başarısız oldu (bu durumda benim evimdi :)). O zamandan beri bunu VBS ile yeniden yazdılar.
Joey

25
bunun herhangi bir pratik kullanımı var mı? Dalgamı geçiyorsun? Bu her zaman diğer kabuklarda kullanılır (sanırım tümü GNU / Linux olanlar) ve çok kullanışlıdır.
Piotr Dobrogost

1
@PiotrDobrogost Sanırım demeye çalıştığı şey, bash betiklerinin geçmişin korkunç bir kalıntısı olduğuydu (Bir programın çıktısını yakalamak için bir for döngüsü kullanmanız gerekiyor mu? Cidden mi?) Değişken kullanmaya ihtiyaç duyduğunuzda, PowerShell gibi daha modern bir şey kullanmalısınız.
Ajedi32

3
Aslında pratik bir kullanımı var ... bir nevi. Belirli bir Visual Studio yolunu bulmak için bir PowerShell betiği kullanmak istiyorum, ancak bu yoldan ihtiyacım olan şey, editbin'i çağırabilmem için bir grup env değişkenini ayarlayan bir toplu iş dosyası ... Bu yüzden yolu bulmam gerekiyor ve onu çağıran örneğe geri götür, cmdböylece orada çalıştırabilirim. ... Evet, bu sesler kadar korkunç. Visual Studio bazen ağlamak istememe neden oluyor. @ Ajedi32 Bence sen söylemek anlamına toplu komut geçmişin korkunç kalıntı bulunmaktadır. ;)
jpmc26

85

Komuta için alçakgönüllülük yıllar boyunca bazı ilginç yetenekler biriktirdi:

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

"delims="Varsayılan boşluğun ve sekme sınırlayıcıların üzerine yazdığını ve böylece tarih komutunun çıktısının bir kerede yuvarlanacağını unutmayın.

Çok satırlı çıktıyı yakalamak için, esasen tek satırlık bir çıktı olabilir (elde edilen değişkende sınırlayıcı olarak lf değişkenini kullanarak):

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%

Borulu bir ifade yakalamak için şunu kullanın ^|:

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

1
@ PabloG'nin cevabında olduğu gibi, bu sadece bu durumda "tarih / t" komutunun son çıktı satırını almak için çalışacaktır.
John Meagher

11
Cevabınızı yalnızca çift yüzde işaretleri kullandığımda işe yaradığını buldum, yaniFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski

18
@Rabarberski: forKomut satırına doğrudan bir komut yazarsanız, tek bir komut kullanırsınız %. Bir toplu iş dosyasında kullanırsanız, kullanırsınız %%.
indiv

@tardate: Komutun argüman olarak iletilmesi gerekiyorsa, betiğin nasıl görüneceğini söyler misiniz %, örneğin:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k

1
@degenerate Komut, datekullanılan komutun Cygwin'den gelmesi koşuluyla geçerlidir . Katılıyorum, bundan bahsetmeliydim.
dma_k

24

Mevcut dizini almak için şunu kullanabilirsiniz:

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

Yine de bir geçici dosya kullanıyor, bu yüzden en güzel değil, ama kesinlikle işe yarıyor! 'CD' geçerli dizini 'tmpFile'a koyar,' SET 'tmpFile içeriğini yükler.

İşte "diziler" ile birden çok satır için bir çözüm:

@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

Ancak daha güçlü başka bir kabuğa geçmeyi veya bunun için bir uygulama oluşturmayı düşünebilirsiniz. Toplu iş dosyalarının olanaklarını biraz genişletiyor.


Komuttan birden çok satırı yakalamak için çalışan bir varyasyon var mı?
John Meagher

6
Mevcut dizini almak için echo% CD% kullanabilirsiniz
Joe

9

SETkomutu parametresiyle kullanmanız /Pve çıktınızı ona yönlendirmeniz gerekir. Örneğin http://www.ss64.com/nt/set.html adresine bakın . CMD için çalışacak, .BAT dosyalarından emin değil

Bir yorumdan bu gönderiye:

Bu bağlantı, başlangıç satırına Set /P _MyVar=<MyFilename.txtayarlanacağını söyleyen " " komutuna sahiptir . Bu, " " ile " " olarak kullanılabilir . Ancak çıktının tamamını değil, yalnızca çıktının ilk satırını alacak_MyVarMyFilename.txtmyCmd > tmp.txtset /P myVar=<tmp.txt


2
Bu bağlantı "Set / P _MyVar = <MyFilename.txt" komutuna sahiptir, bu da _MyVar'ı MyFilename.txt'den ilk satıra ayarlayacağını söyler. Bu, "set / P myVar = <tmp.txt" ile "myCmd> tmp.txt" olarak kullanılabilir. Ancak çıktının tamamını değil, yalnızca çıktının ilk satırını alır.
John Meagher

Bu cevap benim gibi yeni

5

En son dosyayı "V" ortam değişkeninde ayarlama örneği

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

bir toplu iş dosyasında döngü değişkeninde çift önek kullanmanız gerekir:

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

2
Bu yaklaşımı daha önce görmüştüm, ama gerçekten hantal görünüyor. Ayrıca, değişkendeki komuttan yalnızca son çıktı satırını yakalaması sorunu da vardır.
John Meagher

3

Sadece komuttaki sonucu FORkullanın. Örneğin (bir toplu iş dosyası içinde):

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

İstediğiniz %%Ideğer olarak kullanabilirsiniz . Sadece bu gibi: %%I.

Ve önceden %%Iboşluk veya CR karakteri içermez ve karşılaştırmalar için kullanılabilir !!


2

Bash'de bir komutun sonucunu argüman olarak kullanma bölümünde sağlanan çözümü arıyorsanız ?

o zaman işte kod:

@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
  • Bu kendisini pwd ile aynı CD komutunun sonucuyla çağıracaktır.
  • Parametrelerde dize çıkarma işlemi dosya adını / klasörü döndürür.
  • Bu klasörün içeriğini alın ve dosyaadı.txt dosyasına ekleyin

[Kredi] : Diğer tüm yanıtlar ve Windows XP komutları sayfasındaki bazı araştırmalar için teşekkürler .


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

Cevap gönderdiğiniz için teşekkürler! Bir kod parçacığı soruyu yanıtlayabilirken, etrafa açıklama vb. Gibi bazı ek bilgiler eklemek yine de harika.
j0k

2

Yukarıdaki çözümlere bir açıklama eklemek istiyorum:

Tüm bu sözdizimleri, KOMUTANIZ YOLDA BULUNDUĞUNDA veya KOMUT, BOŞLUKLAR VEYA ÖZEL KARAKTERLER OLMAYAN bir cmdyoluysa mükemmel şekilde çalışır.

Ancak, yolun özel karakterler içeren bir klasörde bulunan çalıştırılabilir bir komutu kullanmaya çalışırsanız, komut yolunuzu çift tırnak işareti (") içine almanız gerekir ve bu durumda FOR / F sözdizimi çalışmaz.

Örnekler:

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

veya

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

veya

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

Bu durumda, bir komutu kullanmak ve sonucunu bir değişkene kaydetmek için bulduğum tek çözüm, varsayılan dizini (geçici olarak) komutun kendisine ayarlamaktır:

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%

Sonuç daha sonra doğrudur:

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

Elbette yukarıdaki örnekte, toplu komut dosyamın "% ~ d0% ~ p0" sözdizimini kullanabilmem için yürütülebilir komutumla aynı klasörde bulunduğunu varsayıyorum. Sizin durumunuz bu değilse, komut yolunuzu bulmanın ve varsayılan dizini yoluna değiştirmenin bir yolunu bulmanız gerekir.

Not: Merak edenler için, burada kullanılan örnek komut (bir klasör seçmek için) FOLDERBROWSE.EXE'dir. Bunu f2ko.de ( http://f2ko.de/en/cmd.php ) web sitesinde buldum .

Karmaşık bir yoldan erişilebilen bu tür komutlar için daha iyi bir çözüme sahip biri varsa, bunu duymaktan çok memnun olacağım.

Gilles


Komutunuza ile önek ekleyebilirsiniz CALL.
Yolda

@jeb: ÇOK TEŞEKKÜR EDERİZ! Şimdi kodum < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> mükemmel çalışıyor.
Gilles Maisonneuve

1

Tüm çıktıları tek bir değişkende yakalayabilirsiniz, ancak satırlar gerçek bir CR-LF yerine seçtiğiniz bir karakterle (aşağıdaki örnekte #) ayrılacaktır.

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

İkinci sürüm, içeriği satır satır yazdırmanız gerekiyorsa. Bu, "dir / b" den çift çıktı satırlarının olmayacağı gerçeğinden avantajlıdır, bu nedenle genel durumda çalışmayabilir.

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

sonuç 'TXT: hola'dır


0

forKomutu kullanmalısınız , işte bir örnek:

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

ve o zaman kullanabilirsiniz call :output "Command goes here"çıktı %output%değişkende olacaktır.

Not: Çok satırlı bir komut çıktınız varsa, bu araç setçok satırlı komutunuzun son satırına çıktı verecektir .


-1

Lütfen komut çıktısıyla neler yapabileceğinizi açıklayan bu http://technet.microsoft.com/en-us/library/bb490982.aspx sayfasına bakın .


1
Bu makale yalnızca yeniden yönlendirme ve ilgili konuları kapsar. Bir komutun çıktısının nasıl alınacağı ve bir değişkene nasıl alınacağı sorusuna cevap vermez.
John Meagher

3
Cevabını kullanarak şunu git pull>0 set /P RESULTVAR=<0 buldum : edit: Sanırım burada satır sonlarını nasıl kullanacağımı bilmiyorum ... her komut kendi satırında.
RibeiroBreno
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.