ฉันต้องการรับผลลัพธ์ของคำสั่งเป็นตัวแปรในสคริปต์แบตช์ของ Windows (ดูวิธีรับผลลัพธ์ของคำสั่งใน bashสำหรับ bash scripting ที่เทียบเท่า) วิธีแก้ปัญหาที่จะทำงานในไฟล์. bat เป็นที่ต้องการ แต่ยินดีต้อนรับโซลูชันสคริปต์ Windows ทั่วไปอื่น ๆ
ฉันต้องการรับผลลัพธ์ของคำสั่งเป็นตัวแปรในสคริปต์แบตช์ของ Windows (ดูวิธีรับผลลัพธ์ของคำสั่งใน bashสำหรับ bash scripting ที่เทียบเท่า) วิธีแก้ปัญหาที่จะทำงานในไฟล์. bat เป็นที่ต้องการ แต่ยินดีต้อนรับโซลูชันสคริปต์ Windows ทั่วไปอื่น ๆ
คำตอบ:
หากคุณต้องจับเอาต์พุตคำสั่งทั้งหมดคุณสามารถใช้ชุดงานดังนี้:
@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)
cmd
เพื่อให้ฉันสามารถเรียกใช้ที่นั่นได้ ... ใช่มันแย่พอ ๆ กับเสียง Visual Studio ทำให้ฉันอยากจะร้องไห้ในบางครั้ง @ Ajedi32 ฉันคิดว่าคุณตั้งใจจะบอกว่าสคริปต์แบตช์เป็นสิ่งที่น่ากลัวในอดีต ;)
อ่อนน้อมถ่อมตนสำหรับคำสั่งได้สะสมความสามารถที่น่าสนใจบางปีที่ผ่านมา:
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"
FOR /F "delims=" %%i IN ('date /t') DO set today=%%i
for
คำสั่งตรงบรรทัดคำสั่งคุณจะใช้ไฟล์%
. หากคุณใช้ในไฟล์แบตช์คุณจะใช้%%
.
%
เช่น:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
date
คำสั่งที่ใช้มาจาก Cygwin ฉันเห็นด้วยฉันควรจะพูดถึงเรื่องนั้น
ในการรับไดเร็กทอรีปัจจุบันคุณสามารถใช้สิ่งนี้:
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
แต่คุณอาจต้องการพิจารณาย้ายไปใช้เชลล์อื่นที่มีประสิทธิภาพมากกว่าหรือสร้างแอปพลิเคชันสำหรับสิ่งนี้ มันยืดความเป็นไปได้ของไฟล์แบตช์ได้ไม่น้อย
คุณต้องใช้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
" ได้ แต่จะได้เฉพาะบรรทัดแรกของเอาต์พุตไม่ใช่เอาต์พุตทั้งหมด
ตัวอย่างการตั้งค่าในตัวแปรสภาพแวดล้อม "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
เพียงแค่ใช้ผลลัพธ์จากFOR
คำสั่ง ตัวอย่างเช่น (ภายในไฟล์แบตช์):
for /F "delims=" %%I in ('dir /b /a-d /od FILESA*') do (echo %%I)
คุณสามารถใช้%%I
เป็นค่าที่คุณต้องการ เช่นนี้: %%I
.
และล่วงหน้า%%I
ไม่มีการเว้นวรรคหรือตัวอักษร CR และสามารถใช้เปรียบเทียบได้ !!
หากคุณกำลังมองหาโซลูชันที่ให้ไว้ในการใช้ผลลัพธ์ของคำสั่งเป็นอาร์กิวเมนต์ใน 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
[เครดิต] : ขอบคุณสำหรับคำตอบอื่น ๆ และข้อมูลบางส่วนในหน้าคำสั่งของWindows XP
@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%"
ฉันต้องการเพิ่มข้อสังเกตในการแก้ปัญหาข้างต้น:
ไวยากรณ์ทั้งหมดเหล่านี้ทำงานได้ดีอย่างสมบูรณ์หากพบคำสั่งของคุณในเส้นทางหรือหากคำสั่งนั้นเป็น 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 ไม่ทำงานหากเส้นทางมีช่องว่าง
CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"
> ทำงานได้อย่างสมบูรณ์
คุณสามารถจับเอาต์พุตทั้งหมดในตัวแปรเดียว แต่บรรทัดจะถูกคั่นด้วยอักขระที่คุณเลือก (# ในตัวอย่างด้านล่าง) แทนที่จะเป็น 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=!
)
)
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
set TXT=%%i
)
echo 'TXT: %TXT%'
ผลลัพธ์คือ 'TXT: hola'
คุณควรใช้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
บรรทัดเครื่องมือนี้จะส่งผลลัพธ์ไปยังบรรทัดสุดท้ายของคำสั่งมัลติไลน์ของคุณ
โปรดดูที่http://technet.microsoft.com/en-us/library/bb490982.aspxซึ่งอธิบายถึงสิ่งที่คุณสามารถทำได้ด้วยเอาต์พุตคำสั่ง
git pull>0 set /P RESULTVAR=<0
แก้ไข: ฉันเดาว่าฉันไม่รู้วิธีใช้ตัวแบ่งบรรทัดที่นี่ ... แต่ละคำสั่งอยู่ในบรรทัดของตัวเอง