Nhận danh sách các đối số được thông qua trong tập lệnh bó Windows (.bat)


405

Tôi muốn tìm một bản sao Windows cho Bash $@chứa một danh sách tất cả các đối số được truyền vào một tập lệnh.

Hay tôi phải bận tâm shift?

Câu trả lời:


622

dancavallaro có quyền, %*cho tất cả các tham số dòng lệnh (không bao gồm tên tập lệnh). Bạn cũng có thể tìm thấy những điều hữu ích:

%0- lệnh sử dụng để gọi các tập tin thực thi (có thể là foo, ..\foo, c:\bats\foo.bat, vv)
%1là tham số dòng lệnh đầu tiên,
%2là tham số dòng lệnh thứ hai,
và vân vân cho đến khi %9(và SHIFTcó thể được sử dụng cho những người sau khi 9).

%~nx0- tên thực của tệp bó, bất kể phương thức gọi (some-batch.bat)
%~dp0- ổ đĩa và đường dẫn đến tập lệnh (d: \ scripts)
%~dpnx0- là tên đường dẫn đủ điều kiện của tập lệnh (d: \ scripts \ some -batch.bat)

Thêm ví dụ về thông tin tại https://www.ss64.com/nt/syntax-args.htmlhttps://www.robvanderwoude.com/parameter.html


11
Lưu ý rằng SHIFT không ảnh hưởng đến% *, do đó không thể sử dụng SHIFT [/ n] cho phần nào trực quan như truy cập toàn bộ dòng lệnh bắt đầu từ tham số thứ n.
Van Jone

4
Một cái gì đó tôi phát hiện ra là %~dpn0sẽ trả lại ổ đĩa và đường dẫn đến tập lệnh cộng với tên của tệp bó, nhưng không phải là phần mở rộng. Tôi thấy điều này đặc biệt hữu ích khi tạo các tập lệnh bó gọi một .ps1tệp có cùng tên. Về cơ bản, tham chiếu dđến ổ đĩa, pđề cập đến đường dẫn, nđề cập đến tên của tệp và xđề cập đến phần mở rộng. Với thông tin đó, bạn có thể làm khá nhiều.
Dan Atkinson ngày

Vì tò mò, giả sử tôi muốn sử dụng ECHO để in ra đường dẫn của tệp nhưng thay thế phần mở rộng của nó, làm thế nào để đi?
Matheus Rocha

2
@MeditusRocha@echo %~n0.my_ext
matt wilkie 17/11/18

@mattwilkie Cảm ơn bạn Tôi đã tìm ra nó bằng cách sử dụng ECHO để xem kết quả sẽ in như thế nào.
Matheus Rocha

149

%* dường như giữ tất cả các đối số được truyền cho kịch bản.


Bất cứ ý tưởng tại sao nó không xử lý một số ký tự như &? Khi tôi cố truy xuất một số đường dẫn của một số tệp đã chọn (sử dụng menu Gửi đến và "% *" để chuyển đối số sang .py), nó sẽ dừng danh sách tại & car character. Vì vậy, nếu ví dụ, tệp thứ hai chứa a &trong tên của nó, phần của tên sau &sẽ bị bỏ qua và cả các tệp còn lại.)
JinSnow

1
@JinSnow Đây &là một nhân vật đặc biệt có nghĩa stop this command and start another one. Một tên tệp chứa & PHẢI được trích dẫn.
Jesse Chisholm

65

%1... %n%*giữ các đối số, nhưng có thể khó truy cập chúng, bởi vì nội dung sẽ được diễn giải.
Do đó, không thể xử lý một cái gì đó như thế này bằng các câu lệnh bình thường

myBatch.bat "&"^&

Mỗi dòng không thành công, vì cmd.exe cố gắng thực thi một trong các ký hiệu (nội dung của% 1 là "&"&)

set var=%1
set "var=%1"
set var=%~1
set "var=%~1"

Nhưng có một cách giải quyết với một tập tin tạm thời

@echo off
SETLOCAL DisableDelayedExpansion

SETLOCAL
for %%a in (1) do (
    set "prompt=$_"
    echo on
    for %%b in (1) do rem * #%1#
    @echo off
) > param.txt
ENDLOCAL

for /F "delims=" %%L in (param.txt) do (
  set "param1=%%L"
)
SETLOCAL EnableDelayedExpansion
set "param1=!param1:*#=!"
set "param1=!param1:~0,-2!"
echo %%1 is '!param1!'

Thủ thuật là kích hoạt echo onvà mở rộng câu lệnh %1sau rem(cũng hoạt động với% 2 ..% *).
Nhưng để có thể chuyển hướng đầu ra của echo on, bạn cần hai FOR-LOOPS.

Các ký tự phụ * #được sử dụng để an toàn đối với các nội dung như /?(sẽ hiển thị trợ giúp cho REM).
Hoặc một dấu mũ ^ ở cuối dòng có thể hoạt động như một nhân vật đa dòng.

FOR / F phải hoạt động với việc mở rộng bị trì hoãn, các nội dung khác với "!" sẽ bị phá hủy
Sau khi loại bỏ các ký tự phụ param1và bạn đã nhận được nó.

Và để sử dụng param1một cách an toàn, cho phép mở rộng bị trì hoãn.

Chỉnh sửa: Một nhận xét cho% 0

%0chứa lệnh được sử dụng để gọi lô, đồng thời bảo toàn trường hợp như trong FoO.BaT
Nhưng sau khi gọi hàm %0và cũng %~0chứa tên hàm (hoặc tốt hơn là chuỗi được sử dụng để gọi hàm).
Nhưng với %~f0bạn vẫn có thể nhớ lại tên tệp.

@echo off
echo main %0, %~0, %~f0
call :myLabel+xyz
exit /b

:MYlabel
echo func %0, %~0, %~f0
exit /b

Đầu ra

main test.bat, test.bat, C:\temp\test.bat
func :myLabel+xyz, :myLabel+xyz, C:\temp\test.bat

6
+++ 1 OMG - Thủ %~f0thuật này hoàn toàn bất ngờ, thú vị và có khả năng rất hữu ích :-) Không ngạc nhiên, các công cụ sửa đổi khác hoạt động theo cùng một cách, luôn hoạt động trên tệp bó cha, ngay cả khi trong chương trình con được gọi. Điều này có vẻ xứng đáng với Hỏi & Đáp của riêng nó - "Làm thế nào để truy cập tên của lô đang chạy khi trong chương trình con được gọi là?"
dbenham

Nếu tôi nhớ chính xác, bạn có thể sử dụng cuộc gọi với các đối số và những cuộc gọi đó sẽ được lưu trữ trong% 1,% 2, ...% n giống như khi bạn chạy tập lệnh.
Nulano

49

Tôi thấy rằng lần sau khi bạn cần tra cứu những thông tin này. Thay vì mở trình duyệt và google nó, bạn chỉ cần nhập call /?cmd và bạn sẽ nhận được:

...

%* in a batch script refers to all the arguments (e.g. %1 %2 %3
    %4 %5 ...)

Substitution of batch parameters (%n) has been enhanced.  You can
now use the following optional syntax:

    %~1         - expands %1 removing any surrounding quotes (")
    %~f1        - expands %1 to a fully qualified path name
    %~d1        - expands %1 to a drive letter only
    %~p1        - expands %1 to a path only
    %~n1        - expands %1 to a file name only
    %~x1        - expands %1 to a file extension only
    %~s1        - expanded path contains short names only
    %~a1        - expands %1 to file attributes
    %~t1        - expands %1 to date/time of file
    %~z1        - expands %1 to size of file
    %~$PATH:1   - searches the directories listed in the PATH
                   environment variable and expands %1 to the fully
                   qualified name of the first one found.  If the
                   environment variable name is not defined or the
                   file is not found by the search, then this
                   modifier expands to the empty string

The modifiers can be combined to get compound results:

    %~dp1       - expands %1 to a drive letter and path only
    %~nx1       - expands %1 to a file name and extension only
    %~dp$PATH:1 - searches the directories listed in the PATH
                   environment variable for %1 and expands to the
                   drive letter and path of the first one found.
    %~ftza1     - expands %1 to a DIR like output line

In the above examples %1 and PATH can be replaced by other
valid values.  The %~ syntax is terminated by a valid argument
number.  The %~ modifiers may not be used with %*

20

Cách để truy xuất tất cả các đối số vào một tập lệnh là ở đây:

@ECHO off
ECHO The %~nx0 script args are...
for %%I IN (%*) DO ECHO %%I
pause

2
Không thực sự, %%Iđược giải thích và có thể phá vỡ kịch bản của bạn.
Boris Brodski

5

Đây là một cách khá đơn giản để lấy các đối số và đặt chúng làm các vars env. Trong ví dụ này tôi sẽ chỉ gọi chúng là Chìa khóa và Giá trị.

Lưu ví dụ mã sau đây là "args.bat". Sau đó gọi tệp bó bạn đã lưu từ một dòng lệnh. ví dụ: arg.bat --x 90 --y 120

Tôi đã cung cấp một số lệnh echo để hướng dẫn bạn qua quy trình. Nhưng kết quả cuối cùng là --x sẽ có giá trị 90 và --y sẽ có giá trị 120 (đó là nếu bạn chạy ví dụ như được chỉ định ở trên ;-)).

Sau đó, bạn có thể sử dụng câu lệnh có điều kiện 'nếu được xác định' để xác định xem có chạy khối mã của mình hay không. Vì vậy, hãy nói run: "arg.bat --x hello-world" Sau đó tôi có thể sử dụng câu lệnh "NẾU DEFINED --x echo% - x%" và kết quả sẽ là "hello-world". Nó sẽ có ý nghĩa hơn nếu bạn chạy lô.

@setlocal enableextensions enabledelayedexpansion
@ECHO off
ECHO.
ECHO :::::::::::::::::::::::::: arg.bat example :::::::::::::::::::::::::::::::
ECHO :: By:      User2631477, 2013-07-29                                   ::
ECHO :: Version: 1.0                                                         ::
ECHO :: Purpose: Checks the args passed to the batch.                        ::
ECHO ::                                                                      ::
ECHO :: Start by gathering all the args with the %%* in a for loop.          ::
ECHO ::                                                                      ::
ECHO :: Now we use a 'for' loop to search for our keys which are identified  ::
ECHO :: by the text '--'. The function then sets the --arg ^= to the next    ::
ECHO :: arg. "CALL:Function_GetValue" ^<search for --^> ^<each arg^>         ::
ECHO ::                                                                      ::
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

ECHO.

ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO :: From the command line you could pass... arg.bat --x 90 --y 220       ::
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.
ECHO.Checking Args:"%*"

FOR %%a IN (%*) do (
    CALL:Function_GetValue "--","%%a" 
)

ECHO.
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO :: Now lets check which args were set to variables...                   ::
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO :: For this we are using the CALL:Function_Show_Defined "--x,--y,--z"   ::
ECHO ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.
CALL:Function_Show_Defined "--x,--y,--z"
endlocal
goto done

:Function_GetValue

REM First we use find string to locate and search for the text.
echo.%~2 | findstr /C:"%~1" 1>nul

REM Next we check the errorlevel return to see if it contains a key or a value
REM and set the appropriate action.

if not errorlevel 1 (
  SET KEY=%~2
) ELSE (
  SET VALUE=%~2
)
IF DEFINED VALUE (
    SET %KEY%=%~2
    ECHO.
    ECHO ::::::::::::::::::::::::: %~0 ::::::::::::::::::::::::::::::
    ECHO :: The KEY:'%KEY%' is now set to the VALUE:'%VALUE%'                     ::
    ECHO :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ECHO.
    ECHO %KEY%=%~2
    ECHO.
    REM It's important to clear the definitions for the key and value in order to
    REM search for the next key value set.
    SET KEY=
    SET VALUE=
)
GOTO:EOF

:Function_Show_Defined 
ECHO.
ECHO ::::::::::::::::::: %~0 ::::::::::::::::::::::::::::::::
ECHO :: Checks which args were defined i.e. %~2
ECHO :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.
SET ARGS=%~1
for %%s in (%ARGS%) DO (
    ECHO.
    ECHO :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ECHO :: For the ARG: '%%s'                         
    IF DEFINED %%s (
        ECHO :: Defined as: '%%s=!%%s!'                                             
    ) else (
        ECHO :: Not Defined '%%s' and thus has no value.
    )
    ECHO :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    ECHO.
)
goto:EOF

:done

Điều này rất hữu ích!
áo choàng007

3

nhập mô tả hình ảnh ở đây

Để sử dụng vòng lặp để có được tất cả các đối số và trong lô thuần túy:

Quan sát: Để sử dụng mà không có:?*&<>


@echo off && setlocal EnableDelayedExpansion

for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && call set "_arg_[!_cnt!]=!_arg_!")

:: write/test these arguments/parameters ::
for /l %%l in (1 1 !_cnt!)do echo/ The argument n:%%l is: !_arg_[%%l]!

goto :eof 

Mã của bạn đã sẵn sàng để làm một cái gì đó với số đối số mà nó cần, như ...

@echo off && setlocal EnableDelayedExpansion

for %%Z in (%*)do set "_arg_=%%Z" && set/a "_cnt+=1+0" && call set "_arg_[!_cnt!]=!_arg_!"

echo= !_arg_[1]! !_arg_[2]! !_arg_[2]!> log.txt

2

Đoạn mã sau mô phỏng một mảng (' params') - lấy các tham số mà tập lệnh nhận được và lưu trữ chúng trong các biến params_1.. params_n, trong đó n= params_0= số phần tử của mảng:

@echo off

rem Storing the program parameters into the array 'params':
rem Delayed expansion is left disabled in order not to interpret "!" in program parameters' values;
rem however, if a parameter is not quoted, special characters in it (like "^", "&", "|") get interpreted at program launch
set /a count=0
:repeat
    set /a count+=1
    set "params_%count%=%~1"
    shift
    if defined params_%count% (
        goto :repeat
    ) else (
        set /a count-=1
    )    
set /a params_0=count

rem Printing the program parameters stored in the array 'params':
rem After the variables params_1 .. params_n are set with the program parameters' values, delayed expansion can
rem be enabled and "!" are not interpreted in the variables params_1 .. params_n values
setlocal enabledelayedexpansion
    for /l %%i in (1,1,!params_0!) do (
        echo params_%%i: "!params_%%i!"
    )
endlocal

pause
goto :eof

1

Nếu bạn có các tham số trong dấu ngoặc kép chứa khoảng trắng, %*sẽ không hoạt động chính xác. Giải pháp tốt nhất tôi tìm thấy là có một vòng lặp tham gia tất cả các đối số: https://serverfault.com/a/22541

set args=%1
shift
:start
if [%1] == [] goto done
set args=%args% %1
shift
goto start

:done
(use %args% here)

1

Bạn có thể sử dụng ForCommad, để lấy danh sách Arg.

Trợ giúp: For /? Trợ giúp:Setlocal /?

Đây là cách của tôi =

@echo off
::For Run Use This = cmd /c ""Args.cmd" Hello USER Scientist etc"
setlocal EnableDelayedExpansion
set /a Count=0
for %%I IN (%*) DO (
 Echo Arg_!Count! = %%I
 set /a Count+=1 
)
Echo Count Of Args = !Count!
Endlocal

Không cần lệnh Shift.


0
@echo tắt
:khởi đầu

:: Chèn mã của bạn vào đây
echo. %% 1 hiện tại:% ~ 1
:: Kết thúc chèn mã của bạn ở đây

nếu "% ~ 2" NEQ "" (
    ca
    goto: bắt đầu
)

0

Rất nhiều thông tin ở trên đã đưa tôi đến nghiên cứu sâu hơn và cuối cùng là câu trả lời của tôi vì vậy tôi muốn đóng góp những gì tôi đang làm với hy vọng nó sẽ giúp người khác:

  • Tôi cũng muốn chuyển một số lượng biến khác nhau cho một tệp bó để chúng có thể được xử lý trong tệp.

  • Tôi đã ổn khi chuyển chúng vào tệp bó bằng dấu ngoặc kép

  • Tôi muốn chúng được xử lý tương tự như bên dưới - nhưng sử dụng vòng lặp thay vì viết thủ công:

Vì vậy, tôi muốn thực hiện điều này:

prog_ZipDeleteFiles.bat "_appPath=C:\Services\Logs\PCAP" "_appFile=PCAP*.?"

Và thông qua sự kỳ diệu của các vòng lặp thực hiện điều này trong tệp bó:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

Vấn đề tôi gặp phải là tất cả những nỗ lực của tôi để sử dụng vòng lặp for đều không hoạt động. Ví dụ dưới đây:

for /f "tokens* delims= " in %%A (%*) DO (
   set %%A
)

sẽ làm

set "_appPath=C:\Services\Logs\PCAP"

và không:

set "_appPath=C:\Services\Logs\PCAP"
set "_appFile=PCAP*.?"

ngay cả sau khi thiết lập

SETLOCAL EnableDelayedExpansion

Lý do là vòng lặp for đọc toàn bộ dòng và gán tham số thứ hai của tôi cho %% B trong lần lặp đầu tiên của vòng lặp. Bởi vì% * đại diện cho tất cả các đối số, chỉ có một dòng duy nhất để xử lý - chỉ xảy ra một lần vượt qua vòng lặp for. Điều này là do thiết kế hóa ra, và logic của tôi đã sai.

Vì vậy, tôi đã ngừng cố gắng sử dụng một vòng lặp for và đơn giản hóa những gì tôi đang cố gắng làm bằng cách sử dụng if, shift và một câu lệnh goto. Đồng ý một chút hack nhưng nó phù hợp hơn với nhu cầu của tôi. Tôi có thể lặp qua tất cả các đối số và sau đó sử dụng câu lệnh if để thoát khỏi vòng lặp một khi tôi xử lý tất cả chúng.

Tuyên bố chiến thắng cho những gì tôi đã cố gắng thực hiện:

echo on
:processArguments
:: Process all arguments in the order received
if defined %1 then (
    set %1
    shift
    goto:processArguments
) ELSE (
    echo off 
)

CẬP NHẬT - Thay vào đó, tôi phải sửa đổi thành bên dưới, tôi đã phơi bày tất cả các biến môi trường khi cố gắng tham chiếu% 1 và sử dụng shift theo cách này:

echo on
shift
:processArguments
:: Process all arguments in the order received
if defined %0 then (
    set %0
    shift
    goto:processArguments
) ELSE (
    echo off 
)

Tôi đã sai, đã kiểm tra thêm và sau lần lặp thứ 3, lệnh shift của tôi hiển thị tất cả các biến môi trường, phá vỡ các điều trên. Tôi vẫn đang xem xét nếu có một cách xung quanh nó.
John Ahearn

Phải sửa đổi, thay vì sử dụng% 1, ban đầu tôi phải thay đổi một lần và sử dụng% 0 nếu không tôi gặp phải một vấn đề kỳ lạ khi cuối cùng% 1 chứa tất cả các biến môi trường hiện tại.
John Ahearn

0

Đôi khi tôi cần trích xuất một vài tham số dòng lệnh, nhưng không phải tất cả chúng và không phải từ tham số đầu tiên. Hãy giả sử cuộc gọi sau:

Test.bat uno dos tres cuatro cinco seis siete

Tất nhiên, phần mở rộng ".bat" không cần thiết ít nhất là bạn có test.exe trong cùng một thư mục. Những gì chúng tôi muốn là có được đầu ra "tres cuatro cinco" (không có vấn đề nếu một hoặc ba dòng). Mục tiêu là chỉ tôi cần ba tham số và bắt đầu trong tham số thứ ba. Để có một ví dụ đơn giản, hành động cho mỗi người chỉ là "tiếng vang", nhưng bạn có thể nghĩ trong một số hành động phức tạp khác đối với các tham số đã chọn.

Tôi đã tạo ra một số ví dụ, (tùy chọn) để bạn có thể xem cái nào bạn cho là tốt hơn cho mình. Thật không may, không có cách nào hay (hoặc tôi không biết) dựa trên vòng lặp for trong phạm vi như "cho %% i trong (% 3, 1,% 5)".

@echo off 
setlocal EnableDelayedExpansion

echo Option 1: one by one (same line)
echo %3, %4, %5
echo.

echo Option 2: Loop For one by one
for %%a in (%3, %4, %5) do echo %%a
echo.

echo Option 3: Loop For with check of limits
set i=0
for %%a in (%*) do (
    set /A i=i+1
    If !i! GTR 2 if !i! LSS 6 echo %%a
)
echo.

echo Option 4: Loop For with auxiliary list
for /l %%i in (3,1,5) do  (
    set a=%%i
    set b=echo %%
    set b=!b!!a!
    call !b!
)
echo.

echo Option 5: Assigning to an array of elements previously
set e[0]=%0
set i=0 
for %%a in (%*) do (
    set /A i=i+1
    set e[!i!]=%%a
)
for  /l %%i in (3,1,5) do (
    echo !e[%%i]!
)
echo.

echo Option 6: using shift and goto loop. It doesn't work with for loop
set i=2
:loop6
    set /A i=i+1
    echo %3
    shift
    If %i% LSS 5 goto :loop6

Có lẽ bạn có thể tìm thấy nhiều lựa chọn hơn hoặc kết hợp một vài cái. Thưởng thức chúng.


-1

Phiên bản Windows (mặc dù cần socat)

C:\Program Files (x86)\Git\bin>type gitproxy.cmd
socat STDIO PROXY:proxy.mycompany.de:%1:%2,proxyport=3128

thiết lập nó:

C:\Users\exhau\AppData\Roaming\npm>git config --global core.gitproxy gitproxy.cmd
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.