ฉันจะรับผลลัพธ์ของคำสั่งในตัวแปรใน windows ได้อย่างไร


132

ฉันต้องการรับผลลัพธ์ของคำสั่งเป็นตัวแปรในสคริปต์แบตช์ของ Windows (ดูวิธีรับผลลัพธ์ของคำสั่งใน bashสำหรับ bash scripting ที่เทียบเท่า) วิธีแก้ปัญหาที่จะทำงานในไฟล์. bat เป็นที่ต้องการ แต่ยินดีต้อนรับโซลูชันสคริปต์ Windows ทั่วไปอื่น ๆ


9
จอห์นมันเป็นเรื่องยากที่จะหาขันนี้มากคำถามที่มีประโยชน์ คุณช่วยพิจารณาเพิ่มการใช้คำอื่นเช่นHow to capture the output of aa program into a variable in a Windows batch file?
Piotr Dobrogost

3
Google แสดงหน้านี้อยู่ในอันดับที่ 3
René Nyffenegger


@MichaelFreidgeim คำถามนี้ถูกถามจริงเมื่อ 2 ปีก่อนหน้านั้นซ้ำกัน - แต่มีคำถามนี้ซ้ำกันหลายครั้ง ดูความคิดเห็นในstackoverflow.com/questions/6359820/…
icc97

1
@ icc97 "อาจจะซ้ำกัน" เป็นวิธีการทำความสะอาด - เพื่อปิดคำถามที่คล้ายกันและให้คำตอบที่ดีที่สุด วันที่ไม่จำเป็น ดูmeta.stackexchange.com/questions/147643/…หากคุณยอมรับว่าต้องมีคำชี้แจงโปรดลงคะแนนในmeta.stackexchange.com/questions/281980/… หากคุณเห็นรายการที่ซ้ำกันหลายรายการคุณควรเลือกรายการใดรายการหนึ่งเป็น Canonical และโหวตเพื่อปิดรายการอื่น ๆ .
Michael Freidgeim

คำตอบ:


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 โดยคั่นด้วย "!"

@ จอห์น: มีการใช้งานจริงไหม? ฉันคิดว่าคุณควรดู PowerShell หรือภาษาโปรแกรมอื่น ๆ ที่สามารถทำงานสคริปต์ได้อย่างง่ายดาย (Python, Perl, PHP, Ruby)


คำตอบบรรทัดเดียวจะแก้ปัญหาเฉพาะที่ฉันมี ฉันเพิ่งคิดว่ามีตัวเลือกหลายบรรทัด (หรือตัวเลือกบรรทัดเดียวที่ง่ายกว่า) ฉันเดาว่าความสามารถของไฟล์ bat ไม่ได้ยอดเยี่ยมขนาดนั้น ความจำเป็นในการใช้สคริปต์ bat ที่ตัดแอป Java การสร้างคลาสพา ธ เป็นหลัก
John Meagher

ระวังให้มากด้วย GWT ยังพยายามใช้ไฟล์แบตช์สำหรับการเริ่มต้น Java ด้วยคลาสพา ธ เฉพาะซึ่งล้มเหลวอย่างน่าสยดสยองทันทีที่คุณเข้าสู่ไดเรกทอรีที่มีอักขระที่ไม่ใช่ ASCII (ในกรณีนั้นคือบ้านของฉัน :)) ตั้งแต่นั้นพวกเขาเขียนใหม่ด้วย VBS
Joey

25
มีการใช้งานจริงหรือไม่? คุณล้อเล่น? สิ่งนี้ถูกใช้ตลอดเวลาในเชลล์อื่น ๆ (ฉันเดาว่า GNU / Linux ทั้งหมด) และมีประโยชน์มาก
Piotr Dobrogost

1
@PiotrDobrogost ฉันคิดว่าสิ่งที่เขาพยายามจะพูดคือสคริปต์ทุบตีเป็นสิ่งที่น่ากลัวในอดีต (คุณต้องใช้for loopเพื่อจับเอาท์พุทของโปรแกรมอย่างจริงจัง?) และถ้าคุณเคยไปถึงจุดนั้น ที่คุณพบว่าตัวเองจำเป็นต้องใช้ตัวแปรคุณควรใช้สิ่งที่ทันสมัยกว่าเช่น 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" ในกรณีนี้
John Meagher

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

นี่คือวิธีแก้ปัญหาสำหรับหลายบรรทัดด้วย "array's":

@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

แต่คุณอาจต้องการพิจารณาย้ายไปใช้เชลล์อื่นที่มีประสิทธิภาพมากกว่าหรือสร้างแอปพลิเคชันสำหรับสิ่งนี้ มันยืดความเป็นไปได้ของไฟล์แบตช์ได้ไม่น้อย


มีรูปแบบที่สามารถจับภาพหลายบรรทัดจากคำสั่งได้หรือไม่?
John Meagher

6
ในการรับไดเร็กทอรีปัจจุบันคุณสามารถใช้ echo% CD%
Joe

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" แต่จะได้เฉพาะบรรทัดแรกของเอาต์พุตไม่ใช่เอาต์พุตทั้งหมด
John Meagher

คำตอบนี้มีไว้สำหรับ

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
ฉันเคยเห็นแนวทางนี้มาก่อน แต่ดูเหมือนแฮ็คจริงๆ นอกจากนี้ยังมีปัญหาที่จะจับบรรทัดสุดท้ายของเอาต์พุตจากคำสั่งในตัวแปรเท่านั้น
John Meagher

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" ได้ หากนี่ไม่ใช่กรณีของคุณคุณต้องหาวิธีค้นหาเส้นทางคำสั่งของคุณและเปลี่ยนไดเร็กทอรีเริ่มต้นเป็นพา ธ

หมายเหตุ: สำหรับผู้ที่สงสัยคำสั่งตัวอย่างที่ใช้ที่นี่ (เพื่อเลือกโฟลเดอร์) คือ 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

คุณควรใช้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
บทความนั้นครอบคลุมเฉพาะการเปลี่ยนเส้นทางและหัวข้อที่เกี่ยวข้อง มันไม่ได้ตอบคำถามว่าจะเอาผลลัพธ์ของคำสั่งเดียวมาเป็นตัวแปรได้อย่างไร
John Meagher

3
ใช้คำตอบของเขาฉันได้มากับสิ่งนี้: git pull>0 set /P RESULTVAR=<0 แก้ไข: ฉันเดาว่าฉันไม่รู้วิธีใช้ตัวแบ่งบรรทัดที่นี่ ... แต่ละคำสั่งอยู่ในบรรทัดของตัวเอง
RibeiroBreno
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.