MS toplu iş dosyası kullanarak bir değişkenin çıktısını programa atama


291

MS toplu iş dosyası kullanarak bir değişkene bir programın çıktısını atamak gerekiyor.

Yani GNU Bash kabuğunda kullanırdım VAR=$(application arg0 arg1). Windows'da bir toplu iş dosyası kullanarak benzer bir davranışa ihtiyacım var.

Gibi bir şey set VAR=application arg0 arg1.

Yanıtlar:


434

Bunun bir yolu:

application arg0 arg1 > temp.txt
set /p VAR=<temp.txt

Diğeri:

for /f %%i in ('application arg0 arg1') do set VAR=%%i

İlk o Not %içinde %%ikaçmak için kullanılır %ondan sonra ve toplu dosya içinde yerine komut satırında yukarıdaki kodu kullanılırken gereklidir. Düşünün, test.batşöyle bir şey var:

for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%

11
Bu harika bir hile, neden bir boru ile çalışmadığını merak ediyorum
Bill K

25
Bu yalnızca tek bir metin satırı olan çıktı için geçerlidir (sonraki satırlar ilk satır sonundan sonra atlanır).
GroovyCakes

20
@Machta, parens içindeki ifadenin içinde, ondan önce ^ işareti ile kaçmalıdır. Örnek:for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"
Emanuele Del Grande

8
Boşluklu çizgiler için çalışmaz. Örneğin: ('ver') içindeki / f %% i için VAR = %% i ayarını yapın. @Renat yazdığı gibi, "tokens = *" eklemelidir
Yura Shinkarev

2
@GroovyCakes Çıktıdaki birden fazla satır hakkındaki sorunuz yinelenen bir soruda bu yanıtla yanıtlanır
icc97

67

Bu önceki cevaba ek olarak , borular bir düzeltme işareti ifadesinden kaçan bir for ifadesinin içinde kullanılabilir:

    for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i

1
İki önemli nokta: Yakalamak için token kullanın ve borudan kaçmak için şapka kullanın.
Christopher Oezbek

6
CLI üzerinde çalışan ve daha kolay tamir için kopyala yapıştırılabilen eşdeğer sürüm: for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %iAncak genel olarak, usebackqkarmaşık komutları işlemek için kullanılmalıdır.
Amit Naidu

Çıktıdaki boşlukları işlemek için simgeler gerekiyordu.
Mark Ingram

Alıntılar böyle, benim için de çalışır: for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i. Komutun içinde herhangi bir alıntı yoksa benim için daha kolay.
Paul


8

uygulamanızın çıktısının sayısal bir dönüş kodu olduğunu varsayarsak, aşağıdakileri yapabilirsiniz

application arg0 arg1
set VAR=%errorlevel%

5
Ne yazık ki, çıktı bir dizedir.
initialZero

tamam. Bunu gelecek nesiller için saklayacağım, ama geçici bir dosyaya boru çıkışı hakkında konuşan @ jdigital'in bağlantısına bir göz atın.
akf

1
Programın stdout ve stderr çıktıları, tamsayı dönüş değerinden farklıdır. Bir program, konsola bir dize gönderirken (veya bir dosyaya veya başka bir yere yeniden yönlendirilirken) yukarıdaki örnekteki gibi bir tamsayı değeri döndürebilir. Bunlar birbirini dışlamaz ve iki farklı kavramdır.
David Rector

7

Yürütme sırasında: for /f %%i in ('application arg0 arg1') do set VAR=%%ihata alıyordum: %% şu anda beklenmedim. Bir düzeltme olarak, yukarıdaki gibi yürütmek zorunda kaldımfor /f %i in ('application arg0 arg1') do set VAR=%i


9
Bir toplu iş dosyasında ihtiyacınız olan %%ve ihtiyacınız olan bir komut satırındaki bir toplu iş dosyasının dışında%
Jerry Jeremiah

2

Cevaba ek olarak, döngünün ayarlanan bölümünde çıkış yeniden yönlendirme işleçlerini doğrudan kullanamazsınız for(örneğin bir kullanıcıdan stderror çıktısını gizlemek ve daha güzel bir hata mesajı vermek istiyorsanız). Bunun yerine, onlardan bir düzeltme karakteriyle ( ^) kaçmak zorundasınız :

for /f %%O in ('some-erroring-command 2^> nul') do (echo %%O)

Başvuru: Toplu komut dosyası döngüsü için komut çıktısını yeniden yönlendir


1
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION

REM Prefer backtick usage for command output reading:
REM ENABLEDELAYEDEXPANSION is required for actualized
REM  outer variables within for's scope;
REM within for's scope, access to modified 
REM outer variable is done via !...! syntax.

SET CHP=C:\Windows\System32\chcp.com

FOR /F "usebackq tokens=1,2,3" %%i IN (`%CHP%`) DO (
    IF "%%i" == "Aktive" IF "%%j" == "Codepage:" (
        SET SELCP=%%k
        SET SELCP=!SELCP:~0,-1!
    )
)
echo actual codepage [%SELCP%]

ENDLOCAL

(plus1) backticks için açıklama
Sandburg

1

Biraz bash kabuğunun davranışı gibi komut çıktılarının basit bir şekilde yakalanması için bir toplu iş makro kullanabilirsiniz.

Makronun kullanımı basittir ve şöyle görünür

%$set% VAR=application arg1 arg2

Ve borularla bile çalışır

%$set% allDrives="wmic logicaldisk get name /value | findstr "Name""

Makro, değişkeni dizi gibi kullanır ve her satırı ayrı bir dizinde depolar.
Örneklemde %$set% allDrives="wmic logicaldiskaşağıdaki değişkenler yaratılacaktır:

allDrives.Len=5
allDrives.Max=4
allDrives[0]=Name=C:
allDrives[1]=Name=D:
allDrives[2]=Name=F:
allDrives[3]=Name=G:
allDrives[4]=Name=Z:
allDrives=<contains the complete text with line feeds>

Bunu kullanmak için makronun kendisinin nasıl çalıştığını anlamak önemli değildir.

Tam örnek

@echo off
setlocal

call :initMacro

%$set% ipOutput="ipconfig"
call :ShowVariable ipOutput
echo First line is %ipOutput[0]%

echo( 
%$set% driveNames="wmic logicaldisk get name /value | findstr "Name""
call :ShowVariable driveNames

exit /b

:ShowVariable
setlocal EnableDelayedExpansion
for /L %%n in (0 1 !%~1.max!) do (
    echo %%n: !%~1[%%n]!
)
echo(
exit /b

:initMacro
if "!!"=="" (
    echo ERROR: Delayed Expansion must be disabled while defining macros
    (goto) 2>nul
    (goto) 2>nul
)
(set LF=^
%=empty=%
)
(set \n=^^^
%=empty=%
)

set $set=FOR /L %%N in (1 1 2) dO IF %%N==2 ( %\n%
    setlocal EnableDelayedExpansion                                 %\n%
    for /f "tokens=1,* delims== " %%1 in ("!argv!") do (            %\n%
        endlocal                                                    %\n%
        endlocal                                                    %\n%
        set "%%~1.Len=0"                                            %\n%
        set "%%~1="                                                 %\n%
        if "!!"=="" (                                               %\n%
            %= Used if delayed expansion is enabled =%              %\n%
                setlocal DisableDelayedExpansion                    %\n%
                for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                if "!!" NEQ "" (                                    %\n%
                    endlocal                                        %\n%
                    )                                               %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set pathExt=:                                       %\n%
                set path=;                                          %\n%
                set "line=!line:^=^^!"                              %\n%
                set "line=!line:"=q"^""!"                           %\n%
                call set "line=%%line:^!=q""^!%%"                   %\n%
                set "line=!line:q""=^!"                             %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") do (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") Do (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L" !                      %\n%
                        if %%C == 0 (                               %\n%
                            set "%%~1=%%~L" !                       %\n%
                        ) ELSE (                                    %\n%
                            set "%%~1=!%%~1!!LF!%%~L" !             %\n%
                        )                                           %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        ) ELSE (                                                    %\n%
            %= Used if delayed expansion is disabled =%             %\n%
            for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") DO (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") DO (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L"                        %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        )                                                           %\n%
        set /a %%~1.Max=%%~1.Len-1                                  %\n%
)                                                                   %\n%
    ) else setlocal DisableDelayedExpansion^&set argv=

goto :eof

0

Her 5 saniyede bir google.com'a ping yapan ve sonuçları şimdiki zamanla günlüğe kaydeden komut dosyasını yazdım. Burada "commandLineStr" değişkenlerine çıktı bulabilirsiniz (indekslerle birlikte)

@echo off

:LOOPSTART

echo %DATE:~0% %TIME:~0,8% >> Pingtest.log

SETLOCAL ENABLEDELAYEDEXPANSION
SET scriptCount=1
FOR /F "tokens=* USEBACKQ" %%F IN (`ping google.com -n 1`) DO (
  SET commandLineStr!scriptCount!=%%F
  SET /a scriptCount=!scriptCount!+1
)
@ECHO %commandLineStr1% >> PingTest.log
@ECHO %commandLineStr2% >> PingTest.log
ENDLOCAL

timeout 5 > nul

GOTO LOOPSTART
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.