Câu trả lời:
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)
%1
là tham số dòng lệnh đầu tiên,
%2
là tham số dòng lệnh thứ hai,
và vân vân cho đến khi %9
(và SHIFT
có 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.html và https://www.robvanderwoude.com/parameter.html
%~dpn0
sẽ 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 .ps1
tệ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.
@echo %~n0.my_ext
%*
dường như giữ tất cả các đối số được truyền cho kịch bản.
&
? 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.)
&
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.
%1
... %n
Và %*
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 on
và mở rộng câu lệnh %1
sau 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ụ param1
và bạn đã nhận được nó.
Và để sử dụng param1
mộ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
%0
chứ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 %0
và cũng %~0
chứ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 %~f0
bạ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
%~f0
thuậ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à?"
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 %*
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
%%I
được giải thích và có thể phá vỡ kịch bản của bạn.
Đâ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
Để 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
Đ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
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)
Bạn có thể sử dụng For
Commad, để 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.
@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 )
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
)
Đô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.