Làm thế nào để tôi có được kết quả của một lệnh trong một biến trong windows?


132

Tôi đang tìm cách lấy kết quả của một lệnh dưới dạng một biến trong tập lệnh bó của Windows (xem cách lấy kết quả của lệnh trong bash cho tương đương tập lệnh bash). Một giải pháp sẽ hoạt động trong tệp .bat được ưa thích, nhưng các giải pháp kịch bản Windows phổ biến khác cũng được hoan nghênh.


9
John, thật khó để tìm thấy câu hỏi rất hữu ích này. Bạn có thể hài lòng cân nhắc việc thêm phân nhịp thay thế như thế nào để nắm bắt được các đầu ra của aa chương trình vào một biến trong một tập tin thực thi Windows?
Piotr Dobrogost

3
Google hiển thị trang này được xếp hạng 3.
René Nyffalanger


@MichaelFreidgeim câu hỏi này thực sự đã được hỏi 2 năm trước khi trùng lặp - nhưng có nhiều bản sao của câu hỏi này. Xem các nhận xét về stackoverflow.com/questions/6359820/ Cách
icc97

1
@ icc97, "Có thể trùng lặp" là một cách để dọn dẹp - để đóng các câu hỏi tương tự và giữ một câu trả lời tốt nhất. Ngày không cần thiết. Xem meta.stackexchange.com/questions/147643/. Nếu bạn đồng ý rằng nó yêu cầu làm rõ, hãy bỏ phiếu trên meta.stackexchange.com/questions/281980/. Nếu bạn thấy nhiều bản sao, bạn nên chọn một bản sao chính tắc và bỏ phiếu để đóng .
Michael Freidgeim

Câu trả lời:


34

Nếu bạn phải nắm bắt tất cả đầu ra lệnh, bạn có thể sử dụng một lô như thế này:

@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ất cả các dòng đầu ra được lưu trữ trong VAR được phân tách bằng "!".

@ John: có sử dụng thực tế cho việc này không? Tôi nghĩ bạn nên xem PowerShell hoặc bất kỳ ngôn ngữ lập trình nào khác có khả năng thực hiện các tác vụ kịch bản một cách dễ dàng (Python, Perl, PHP, Ruby)


Câu trả lời đơn sẽ giải quyết trường hợp cụ thể mà tôi có. Tôi chỉ hình dung có một tùy chọn nhiều dòng (hoặc một tùy chọn một dòng dễ dàng hơn). Tôi đoán khả năng của các tập tin bat chỉ là không tốt. Sự cần thiết của nó là cho các tập lệnh bat đóng gói các ứng dụng Java. Xây dựng đường dẫn chủ yếu.
John Meagher

Hãy thật cẩn thận với điều đó. GWT cũng đã cố gắng sử dụng các tệp bó để khởi động Java với các đường dẫn lớp cụ thể, điều này đã thất bại kinh khủng ngay khi bạn truy cập vào các thư mục có các ký tự không phải ASCII (trong trường hợp đó là nhà của tôi :)). Họ đã viết lại điều đó với VBS.
Joey

25
Có bất kỳ sử dụng thực tế cho việc này? Bạn đang giỡn đấy à? Cái này được sử dụng mọi lúc trong các shell khác (tất cả các GNU / Linux tôi đoán) và nó rất hữu ích.
Piotr Dobrogost

1
@PiotrDobrogost Tôi nghĩ những gì anh ấy đã cố nói là các tập lệnh bash là một di tích khủng khiếp của quá khứ (Bạn cần sử dụng một vòng lặp for chỉ để nắm bắt đầu ra của một chương trình? Nghiêm túc?), Và nếu bạn đã hiểu nơi bạn thấy mình cần sử dụng các biến, bạn nên sử dụng thứ gì đó hiện đại hơn như PowerShell.
Ajedi32

3
Có một cách sử dụng thực tế, thực sự ... hơi ... Tôi muốn sử dụng tập lệnh PowerShell để tìm đường dẫn Visual Studio cụ thể, nhưng thứ tôi cần ngoài đường dẫn đó là một tệp bó đặt một loạt các env để tôi có thể gọi editbin ... Vì vậy, tôi cần tìm đường dẫn và đưa nó trở lại ví dụ gọi cmdđể tôi có thể chạy nó ở đó. ... Vâng, điều này khủng khiếp như âm thanh. Visual Studio đôi khi khiến tôi muốn khóc. @ Ajedi32 Tôi nghĩ bạn muốn nói rằng các kịch bản hàng loạt là một di tích khủng khiếp của quá khứ. ;)
jpmc26

85

Sự khiêm tốn cho mệnh lệnh đã tích lũy một số khả năng thú vị trong những năm qua:

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

Lưu ý rằng "delims="ghi đè không gian mặc định và dấu phân cách tab để đầu ra của lệnh date bị ngấu nghiến cùng một lúc.

Để nắm bắt đầu ra đa dòng, về cơ bản nó vẫn có thể là một lớp lót (sử dụng biến lf làm dấu phân cách trong biến kết quả):

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%

Để chụp biểu thức đường ống, sử dụng ^|:

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

1
Như với câu trả lời của @ PabloG, điều này sẽ chỉ hoạt động để có được dòng đầu ra cuối cùng từ lệnh, "ngày / t" trong trường hợp này.
John Meagher

11
Tôi thấy câu trả lời của bạn chỉ hoạt động khi tôi sử dụng hai dấu phần trăm, tức làFOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski

18
@Rabarberski: Nếu bạn gõ một forlệnh thẳng trên dòng lệnh, bạn sử dụng một lệnh %. Nếu bạn sử dụng nó trong một tập tin hàng loạt, bạn sử dụng %%.
indiv

@tardate: Bạn có thể vui lòng cho biết kịch bản sẽ trông như thế nào không, nếu lệnh cần được truyền đối số với %, ví dụ:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k

1
@degenerate Lệnh hợp lệ với điều kiện là datelệnh được sử dụng đến từ Cygwin. Tôi đồng ý tôi nên đã đề cập đến điều đó.
dma_k

24

Để có được thư mục hiện tại, bạn có thể sử dụng:

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

Mặc dù nó đang sử dụng một tệp tạm thời, vì vậy nó không phải là đẹp nhất, nhưng nó chắc chắn hoạt động! 'CD' đặt thư mục hiện tại vào 'tmpFile', 'SET' tải nội dung của tmpFile.

Đây là một giải pháp cho nhiều dòng với "mảng":

@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

Nhưng bạn có thể muốn xem xét chuyển sang một trình bao mạnh hơn khác hoặc tạo một ứng dụng cho công cụ này. Nó kéo dài khả năng của các tệp bó khá nhiều.


Có một biến thể sẽ hoạt động để nắm bắt nhiều dòng từ lệnh?
John Meagher

6
Để có được thư mục hiện tại, bạn có thể sử dụng echo% CD%
Joe

9

bạn cần sử dụng SETlệnh với tham số /Pvà hướng đầu ra của bạn tới nó. Ví dụ: xem http://www.ss64.com/nt/set.html . Sẽ hoạt động cho CMD, không chắc chắn về các tệp .BAT

Từ một bình luận cho bài viết này:

Liên kết đó có lệnh " Set /P _MyVar=<MyFilename.txt" cho biết nó sẽ được đặt thành _MyVardòng đầu tiên từ đó MyFilename.txt. Điều này có thể được sử dụng như " myCmd > tmp.txt" với " set /P myVar=<tmp.txt". Nhưng nó sẽ chỉ nhận được dòng đầu tiên của đầu ra, không phải tất cả đầu ra


2
Liên kết đó có lệnh "Set / P _MyVar = <MyFilename.txt" cho biết nó sẽ đặt _MyVar thành dòng đầu tiên từ MyFilename.txt. Điều này có thể được sử dụng như "myCmd> tmp.txt" với "set / P myVar = <tmp.txt". Nhưng nó sẽ chỉ nhận được dòng đầu tiên của đầu ra, không phải tất cả đầu ra.
John Meagher

Câu trả lời này dành cho những người mới bắt đầu như tôi

5

Ví dụ để đặt trong biến môi trường "V" tệp gần đây nhất

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

trong một tệp bó, bạn phải sử dụng tiền tố kép trong biến vòng lặp:

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

2
Tôi đã thấy cách tiếp cận này trước đây, nhưng nó có vẻ rất hack. Nó cũng có một vấn đề là nó sẽ chỉ bắt được dòng đầu ra cuối cùng từ lệnh trong biến.
John Meagher

3

Chỉ cần sử dụng kết quả từ FORlệnh. Ví dụ: (bên trong một tệp bó):

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

Bạn có thể sử dụng %%Inhư giá trị bạn muốn. Chỉ như thế này : %%I.

Và trước %%Iđó không có bất kỳ khoảng trắng hoặc ký tự CR nào và có thể được sử dụng để so sánh !!


2

Nếu bạn đang tìm kiếm giải pháp được cung cấp trong Sử dụng kết quả của lệnh làm đối số trong bash?

đây là đoạn mã:

@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
  • Điều này sẽ tự gọi với kết quả của lệnh CD, giống như pwd.
  • Khai thác chuỗi trên các tham số sẽ trả về tên tệp / thư mục.
  • Lấy nội dung của thư mục này và nối vào filename.txt

[Tín dụng] : Nhờ tất cả các câu trả lời khác và một số hoạt động đào trên trang lệnh 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%"

Cảm ơn đã gửi câu trả lời! Mặc dù một đoạn mã có thể trả lời câu hỏi, thật tuyệt khi thêm một số thông tin bổ sung xung quanh, như giải thích, v.v.
j0k

2

Tôi muốn thêm một nhận xét cho các giải pháp trên:

Tất cả các cú pháp này hoạt động hoàn toàn tốt NẾU QUYỀN CỦA BẠN ĐƯỢC TÌM KIẾM TRONG ĐƯỜNG hoặc NẾU QUYỀN LÀ một cmdpath KHÔNG CÓ SPACES HOẶC ĐẶC ĐIỂM ĐẶC BIỆT.

Nhưng nếu bạn cố gắng sử dụng một lệnh thực thi nằm trong thư mục chứa đường dẫn chứa các ký tự đặc biệt thì bạn sẽ cần phải đóng đường dẫn lệnh của mình thành dấu ngoặc kép (") và sau đó cú pháp FOR / F không hoạt động.

Ví dụ:

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

hoặc là

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

hoặc là

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

Trong trường hợp đó, giải pháp duy nhất tôi tìm thấy để sử dụng lệnh và lưu trữ kết quả của nó trong một biến là đặt (tạm thời) thư mục mặc định thành chính lệnh đó:

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%

Kết quả là chính xác:

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

Tất nhiên trong ví dụ trên, tôi giả sử rằng tập lệnh bó của tôi nằm trong cùng thư mục với một trong những lệnh thực thi của tôi để tôi có thể sử dụng cú pháp "% ~ d0% ~ p0". Nếu đây không phải là trường hợp của bạn, thì bạn phải tìm cách xác định vị trí đường dẫn lệnh của mình và thay đổi thư mục mặc định thành đường dẫn của nó.

NB: Đối với những người thắc mắc, lệnh mẫu được sử dụng ở đây (để chọn thư mục) là FOLDERBROWSE.EXE. Tôi tìm thấy nó trên trang web f2ko.de ( http://f2ko.de/en/cmd.php ).

Nếu bất cứ ai có một giải pháp tốt hơn cho loại lệnh đó có thể truy cập thông qua một đường dẫn phức tạp, tôi sẽ rất vui mừng khi nghe về nó.

Gilles


Bạn có thể tiền tố lệnh của bạn với CALL. FOR / F không làm việc nếu con đường có không gian
Jeb

@jeb: CẢM ƠN BẠN RẤT NHIỀU! Bây giờ mã của tôi < CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> hoạt động hoàn hảo.
Gilles Maisonneuve

1

Bạn có thể nắm bắt tất cả đầu ra trong một biến, nhưng các dòng sẽ được phân tách bằng một ký tự bạn chọn (# trong ví dụ bên dưới) thay vì CR-LF thực tế.

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

Phiên bản thứ hai, nếu bạn cần in nội dung ra từng dòng một. Điều này có lợi cho thực tế là sẽ không có dòng đầu ra trùng lặp từ "dir / b", vì vậy nó có thể không hoạt động trong trường hợp chung.

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

kết quả là 'TXT: hola'


0

Bạn nên sử dụng forlệnh, đây là một ví dụ:

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

và bạn có thể sử dụng call :output "Command goes here"thì đầu ra sẽ ở trong %output%biến.

Lưu ý: Nếu bạn có đầu ra lệnh là multiline, công cụ này sẽ setxuất đầu ra đến dòng cuối cùng của lệnh multiline của bạn.


-1

Vui lòng tham khảo http://technet.microsoft.com/en-us/l Library / bb490982.aspx này để giải thích những gì bạn có thể làm với đầu ra lệnh.


1
Bài viết đó chỉ đề cập đến chuyển hướng và các chủ đề liên quan. Nó không trả lời câu hỏi làm thế nào để lấy đầu ra của một lệnh và đưa nó vào một biến.
John Meagher

3
Sử dụng câu trả lời của anh ấy tôi đã đưa ra điều này: git pull>0 set /P RESULTVAR=<0 chỉnh sửa: Tôi đoán, tôi không biết cách sử dụng ngắt dòng ở đây ... mỗi lệnh nằm trên dòng riêng của nó.
RibeiroBreno
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.