Tôi cần chuyển ID và mật khẩu cho một tệp bó tại thời điểm chạy thay vì mã hóa chúng vào tệp.
Đây là dòng lệnh trông như thế nào:
test.cmd admin P@55w0rd > test-log.txt
Tôi cần chuyển ID và mật khẩu cho một tệp bó tại thời điểm chạy thay vì mã hóa chúng vào tệp.
Đây là dòng lệnh trông như thế nào:
test.cmd admin P@55w0rd > test-log.txt
Câu trả lời:
Một mẹo hữu ích khác là sử dụng %*
để chỉ "tất cả". Ví dụ:
echo off
set arg1=%1
set arg2=%2
shift
shift
fake-command /u %arg1% /p %arg2% %*
Khi bạn chạy:
test-command admin password foo bar
tệp bó trên sẽ chạy:
fake-command /u admin /p password admin password foo bar
Tôi có thể có cú pháp hơi sai, nhưng đây là ý tưởng chung.
shift
"bật" đối số từ danh sách. Giả định của OP là %*
sẽ chỉ đưa ra các đối số còn lại, nhưng nó không hoạt động theo cách đó, như @Joey nói.
fake-command /u admin /p password admin password foo bar
. Điều này đã được @Joey chỉ ra từ nhiều năm trước.
Đây là cách tôi đã làm:
@fake-command /u %1 /p %2
Đây là những gì lệnh trông giống như:
test.cmd admin P@55w0rd > test-log.txt
Áp %1
dụng cho tham số đầu tiên %2
(và đây là phần khó khăn) áp dụng cho tham số thứ hai. Bạn có thể có tối đa 9 tham số được truyền theo cách này.
echo %1 %2
và bị loại bỏ bởi trường hợp đơn giản nhất không bị cắt xén với a @
và a fake-command
với thông số, nghĩ rằng chúng ta sẽ nhận được fake-command.bat
nội dung sau này (trong trường hợp đó, quá phức tạp fake-command.bat
có thể phải echo %2 %4
bỏ qua các tên param). Sai, doofus. TL; DR: Đừng ngu ngốc như tôi. 1. echo echo %1 %2 > test.bat
2 test word1 word2
.. 3. Lợi nhuận.
Nếu bạn muốn xử lý thông minh các tham số bị thiếu một cách thông minh, bạn có thể thực hiện một số việc như:
IF %1.==. GOTO No1
IF %2.==. GOTO No2
... do stuff...
GOTO End1
:No1
ECHO No param 1
GOTO End1
:No2
ECHO No param 2
GOTO End1
:End1
Truy cập các tham số lô có thể đơn giản với% 1,% 2, ...% 9 hoặc cũng% *,
nhưng chỉ khi nội dung đơn giản.
Không có cách đơn giản nào cho các nội dung phức tạp như "&"^&
, vì không thể truy cập% 1 mà không gây ra lỗi.
set var=%1
set "var=%1"
set var=%~1
set "var=%~1"
Các dòng mở rộng đến
set var="&"&
set "var="&"&"
set var="&"&
set "var="&"&"
Và mỗi dòng đều thất bại, vì một trong những điều &
nằm ngoài dấu ngoặc kép.
Nó có thể được giải quyết bằng cách đọc từ một tệp tạm thời một phiên bản được chú ý của tham số.
@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% 1 sau một rem
câu lệnh (cũng hoạt động với %2 .. %*
).
Vì vậy, thậm chí "&"&
có thể được lặp lại mà không tạo ra một lỗi, vì nó được nhận xét.
Nhưng để có thể chuyển hướng đầu ra của echo on
, bạn cần hai vòng lặp for.
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, ngay cả sau một rem
.
Sau đó đọc đầu ra tham số rem từ tệp, nhưng cẩn thận.
FOR / F sẽ hoạt động với việc mở rộng bị trì hoãn, các nội dung khác có "!" sẽ bị phá hủy
Sau khi loại bỏ các ký tự phụ param1
, 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.
&
, giải pháp của bạn chỉ hoạt động với nội dung đơn giản
test.bat ^&
và nó thất bại. Chỉ test.bat "&"
hoạt động, nhưng đó không phải là quan điểm của tôi. Bạn không thể sử dụng %*
, %1
một cách an toàn mà không cần kỹ thuật REM
&
và cũng trích dẫn"
Đúng, và đừng quên sử dụng các biến như %%1
khi sử dụng if
và for
băng đảng.
Nếu bạn quên gấp đôi %
, thì bạn sẽ thay thế trong các đối số dòng lệnh (có thể là null) và bạn sẽ nhận được một số thông báo lỗi khá khó hiểu.
if
và for
?
for %%d in (*) do echo %%d
từ dòng lệnh:for %d in (*) do echo %d
@for %%2 in (testing) do @echo %%2 %1
trong một tệp bó, tạo ra testing 1
khi nó được gọi với 1 ( test 1
).
%%1
không truy cập một đối số dòng lệnh và nó cũng sai cho IF
lệnh. Chỉ FOR
lệnh (trong tệp bó) yêu cầu hai phần trăm, nhưng ngay cả khi đó %%1
sẽ xác định tham số FOR và không truy cập đối số
Không cần phải phức tạp hóa nó. Nó chỉ đơn giản là lệnh% 1% 2 tham số, ví dụ,
@echo off
xcopy %1 %2 /D /E /C /Q /H /R /K /Y /Z
echo copied %1 to %2
pause
"Tạm dừng" hiển thị những gì tệp bó đã thực hiện và chờ bạn nhấn phím BẤT K .. Lưu nó dưới dạng xx.bat trong thư mục Windows.
Để sử dụng nó, hãy nhập, ví dụ:
xx c:\f\30\*.* f:\sites\30
Tệp bó này chăm sóc tất cả các tham số cần thiết, như chỉ sao chép các tệp mới hơn, v.v. Tôi đã sử dụng nó từ trước Windows. Nếu bạn muốn xem tên của các tệp, vì chúng đang được sao chép, hãy bỏ qua Q
tham số.
Một người bạn đã hỏi tôi về chủ đề này gần đây, vì vậy tôi nghĩ rằng tôi đã đăng cách tôi xử lý các đối số dòng lệnh trong các tệp bó.
Kỹ thuật này có một chút chi phí như bạn sẽ thấy, nhưng nó làm cho các tệp bó của tôi rất dễ hiểu và nhanh chóng thực hiện. Cũng như hỗ trợ các cấu trúc sau:
>template.bat [-f] [--flag] [/f] [--namedvalue value] arg1 [arg2][arg3][...]
Các jist của nó là có :init
, :parse
và :main
các chức năng.
Ví dụ sử dụng
>template.bat /?
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
USAGE:
test.bat [flags] "required argument" "optional argument"
/?, --help shows this help
/v, --version shows the version
/e, --verbose shows detailed output
-f, --flag value specifies a named parameter value
>template.bat <- throws missing argument error
(same as /?, plus..)
**** ****
**** MISSING "REQUIRED ARGUMENT" ****
**** ****
>template.bat -v
1.23
>template.bat --version
test v1.23
This is a sample batch file template,
providing command-line arguments and flags.
>template.bat -e arg1
**** DEBUG IS ON
UnNamedArgument: "arg1"
UnNamedOptionalArg: not provided
NamedFlag: not provided
>template.bat --flag "my flag" arg1 arg2
UnNamedArgument: "arg1"
UnNamedOptionalArg: "arg2"
NamedFlag: "my flag"
>template.bat --verbose "argument #1" --flag "my flag" second
**** DEBUG IS ON
UnNamedArgument: "argument #1"
UnNamedOptionalArg: "second"
NamedFlag: "my flag"
template.bat
@::!/dos/rocks
@echo off
goto :init
:header
echo %__NAME% v%__VERSION%
echo This is a sample batch file template,
echo providing command-line arguments and flags.
echo.
goto :eof
:usage
echo USAGE:
echo %__BAT_NAME% [flags] "required argument" "optional argument"
echo.
echo. /?, --help shows this help
echo. /v, --version shows the version
echo. /e, --verbose shows detailed output
echo. -f, --flag value specifies a named parameter value
goto :eof
:version
if "%~1"=="full" call :header & goto :eof
echo %__VERSION%
goto :eof
:missing_argument
call :header
call :usage
echo.
echo **** ****
echo **** MISSING "REQUIRED ARGUMENT" ****
echo **** ****
echo.
goto :eof
:init
set "__NAME=%~n0"
set "__VERSION=1.23"
set "__YEAR=2017"
set "__BAT_FILE=%~0"
set "__BAT_PATH=%~dp0"
set "__BAT_NAME=%~nx0"
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedOptionalArg="
set "NamedFlag="
:parse
if "%~1"=="" goto :validate
if /i "%~1"=="/?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="-?" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="--help" call :header & call :usage "%~2" & goto :end
if /i "%~1"=="/v" call :version & goto :end
if /i "%~1"=="-v" call :version & goto :end
if /i "%~1"=="--version" call :version full & goto :end
if /i "%~1"=="/e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="-e" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--verbose" set "OptVerbose=yes" & shift & goto :parse
if /i "%~1"=="--flag" set "NamedFlag=%~2" & shift & shift & goto :parse
if not defined UnNamedArgument set "UnNamedArgument=%~1" & shift & goto :parse
if not defined UnNamedOptionalArg set "UnNamedOptionalArg=%~1" & shift & goto :parse
shift
goto :parse
:validate
if not defined UnNamedArgument call :missing_argument & goto :end
:main
if defined OptVerbose (
echo **** DEBUG IS ON
)
echo UnNamedArgument: "%UnNamedArgument%"
if defined UnNamedOptionalArg echo UnNamedOptionalArg: "%UnNamedOptionalArg%"
if not defined UnNamedOptionalArg echo UnNamedOptionalArg: not provided
if defined NamedFlag echo NamedFlag: "%NamedFlag%"
if not defined NamedFlag echo NamedFlag: not provided
:end
call :cleanup
exit /B
:cleanup
REM The cleanup function is only really necessary if you
REM are _not_ using SETLOCAL.
set "__NAME="
set "__VERSION="
set "__YEAR="
set "__BAT_FILE="
set "__BAT_PATH="
set "__BAT_NAME="
set "OptHelp="
set "OptVersion="
set "OptVerbose="
set "UnNamedArgument="
set "UnNamedArgument2="
set "NamedFlag="
goto :eof
@ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue
Lưu ý: IF "%1"==""
sẽ gây ra vấn đề nếu %1
được đặt trong dấu ngoặc kép.
Trong trường hợp đó, chỉ sử dụng IF [%1]==[]
hoặc, trong NT 4 (SP6) và sau đó, IF "%~1"==""
thay vào đó.
Hãy giữ nó đơn giản.
Đây là tập tin .cmd.
@echo off
rem this file is named echo_3params.cmd
echo %1
echo %2
echo %3
set v1=%1
set v2=%2
set v3=%3
echo v1 equals %v1%
echo v2 equals %v2%
echo v3 equals %v3%
Dưới đây là 3 cuộc gọi từ dòng lệnh.
C:\Users\joeco>echo_3params 1abc 2 def 3 ghi
1abc
2
def
v1 equals 1abc
v2 equals 2
v3 equals def
C:\Users\joeco>echo_3params 1abc "2 def" "3 ghi"
1abc
"2 def"
"3 ghi"
v1 equals 1abc
v2 equals "2 def"
v3 equals "3 ghi"
C:\Users\joeco>echo_3params 1abc '2 def' "3 ghi"
1abc
'2
def'
v1 equals 1abc
v2 equals '2
v3 equals def'
C:\Users\joeco>
FOR %%A IN (%*) DO (
REM Now your batch file handles %%A instead of %1
REM No need to use SHIFT anymore.
ECHO %%A
)
Vòng lặp này trên các tham số lô (% *) hoặc chúng được trích dẫn hoặc không, sau đó lặp lại từng tham số.
test.bat *.txt
, test.bat cat^&dog
hoặcTest.bat /?
Tôi đã viết một tập lệnh read_params đơn giản có thể được gọi là một hàm (hoặc bên ngoài .bat
) và sẽ đặt tất cả các biến vào môi trường hiện tại. Nó sẽ không sửa đổi các tham số ban đầu vì chức năng đang được chỉnh sửa call
với một bản sao của các tham số ban đầu.
Ví dụ, đưa ra lệnh sau:
myscript.bat some -random=43 extra -greeting="hello world" fluff
myscript.bat
sẽ có thể sử dụng các biến sau khi gọi hàm:
call :read_params %*
echo %random%
echo %greeting%
Đây là chức năng:
:read_params
if not %1/==/ (
if not "%__var%"=="" (
if not "%__var:~0,1%"=="-" (
endlocal
goto read_params
)
endlocal & set %__var:~1%=%~1
) else (
setlocal & set __var=%~1
)
shift
goto read_params
)
exit /B
Hạn chế
-force
. Bạn có thể sử dụng -force=true
nhưng tôi không thể nghĩ ra cách cho phép các giá trị trống mà không biết danh sách các tham số trước thời hạn sẽ không có giá trị.Thay đổi
-
trước các tham số.Trong tập tin lô
set argument1=%1
set argument2=%2
echo %argument1%
echo %argument2%
% 1 và% 2 trả về giá trị đối số thứ nhất và thứ hai tương ứng.
Và trong dòng lệnh, vượt qua các đối số
Directory> batchFileName admin P@55w0rd
Đầu ra sẽ là
admin
P@55w0rd
Lấy cảm hứng từ một câu trả lời ở nơi khác bởi @Jon, tôi đã tạo ra một thuật toán tổng quát hơn để trích xuất các tham số, giá trị tùy chọn và công tắc được đặt tên.
Hãy để chúng tôi nói rằng chúng tôi muốn thực hiện một tiện ích foobar
. Nó đòi hỏi một lệnh ban đầu. Nó có một tham số tùy chọn --foo
trong đó có một giá trị tùy chọn (dĩ nhiên không thể là tham số khác); nếu giá trị bị thiếu, nó mặc định là default
. Nó cũng có một tham số tùy chọn --bar
cần một giá trị bắt buộc . Cuối cùng, nó có thể lấy một lá cờ --baz
không có giá trị cho phép. Oh, và những thông số này có thể đến theo thứ tự bất kỳ.
Nói cách khác, nó trông như thế này:
foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]
Đây là một giải pháp:
@ECHO OFF
SETLOCAL
REM FooBar parameter demo
REM By Garret Wilson
SET CMD=%~1
IF "%CMD%" == "" (
GOTO usage
)
SET FOO=
SET DEFAULT_FOO=default
SET BAR=
SET BAZ=
SHIFT
:args
SET PARAM=%~1
SET ARG=%~2
IF "%PARAM%" == "--foo" (
SHIFT
IF NOT "%ARG%" == "" (
IF NOT "%ARG:~0,2%" == "--" (
SET FOO=%ARG%
SHIFT
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE (
SET FOO=%DEFAULT_FOO%
)
) ELSE IF "%PARAM%" == "--bar" (
SHIFT
IF NOT "%ARG%" == "" (
SET BAR=%ARG%
SHIFT
) ELSE (
ECHO Missing bar value. 1>&2
ECHO:
GOTO usage
)
) ELSE IF "%PARAM%" == "--baz" (
SHIFT
SET BAZ=true
) ELSE IF "%PARAM%" == "" (
GOTO endargs
) ELSE (
ECHO Unrecognized option %1. 1>&2
ECHO:
GOTO usage
)
GOTO args
:endargs
ECHO Command: %CMD%
IF NOT "%FOO%" == "" (
ECHO Foo: %FOO%
)
IF NOT "%BAR%" == "" (
ECHO Bar: %BAR%
)
IF "%BAZ%" == "true" (
ECHO Baz
)
REM TODO do something with FOO, BAR, and/or BAZ
GOTO :eof
:usage
ECHO FooBar
ECHO Usage: foobar ^<command^> [--foo [^<fooval^>]] [--bar ^<barval^>] [--baz]
EXIT /B 1
SETLOCAL
để các biến không thoát vào môi trường gọi.SET FOO=
, v.v. trong trường hợp ai đó xác định chúng trong môi trường gọi.%~1
để loại bỏ dấu ngoặc kép.IF "%ARG%" == ""
và không phải IF [%ARG%] == []
bởi vì [
và ]
không chơi sẽ hoàn toàn có giá trị kết thúc trong một khoảng trắng.SHIFT
ở trong một IF
khối, các đối số hiện tại như %~1
không được cập nhật vì chúng được xác định khi IF
phân tích cú pháp. Bạn có thể sử dụng %~1
và %~2
bên trong IF
khối, nhưng nó sẽ gây nhầm lẫn bởi vì bạn có một SHIFT
. Bạn có thể đặt phần SHIFT
cuối của khối cho rõ ràng, nhưng điều đó có thể bị mất và / hoặc gây nhầm lẫn cho mọi người. Vì vậy, "chụp" %~1
và %~1
bên ngoài khối có vẻ tốt nhất.IF NOT "%ARG:~0,2%" == "--"
.SHIFT
khi bạn sử dụng một trong các tham số.SET FOO=%DEFAULT_FOO%
là đáng tiếc, nhưng thay thế sẽ là thêm một khối IF "%FOO%" == "" SET FOO=%DEFAULT_FOO%
bên ngoài IF NOT "%ARG%" == ""
. Tuy nhiên vì đây vẫn là bên trong IF "%PARAM%" == "--foo"
khối, các %FOO%
giá trị sẽ được đánh giá và thiết lập trước khi bạn bước vào khối, vì vậy bạn sẽ không bao giờ phát hiện rằng cả các --foo
tham số đã có mặt và cũng là %FOO%
giá trị đã mất tích.ECHO Missing bar value. 1>&2
gửi thông báo lỗi đến stderr.ECHO:
hoặc một trong các biến thể.Tạo một tệp bó mới (ví dụ: openclass.bat) và viết dòng này vào tệp:
java %~n1
Sau đó đặt tệp bó vào, giả sử, thư mục system32, chuyển đến tệp lớp Java của bạn, nhấp chuột phải, Thuộc tính, Mở bằng ..., sau đó tìm tệp bó của bạn, chọn tệp đó và ...
Nó làm việc cho tôi.
Tái bút: Tôi không thể tìm cách đóng cửa sổ cmd khi đóng lớp Java. Bây giờ ...
start /wait java %~n1
Giải pháp đơn giản (mặc dù câu hỏi đã cũ)
Test1.bat
echo off
echo "Batch started"
set arg1=%1
echo "arg1 is %arg1%"
echo on
pause
CallTest1.bat
call "C:\Temp\Test1.bat" pass123
đầu ra
YourLocalPath>call "C:\Temp\test.bat" pass123
YourLocalPath>echo off
"Batch started"
"arg1 is pass123"
YourLocalPath>pause
Press any key to continue . . .
Trong đó YourLocalPath là đường dẫn thư mục hiện tại.
Để giữ cho mọi thứ đơn giản lưu trữ lệnh param trong biến và sử dụng biến để so sánh.
Nó không chỉ đơn giản để viết mà còn đơn giản để duy trì vì vậy nếu sau này một người khác hoặc bạn đọc kịch bản của bạn sau một thời gian dài, nó sẽ dễ hiểu và duy trì.
Để viết mã nội tuyến: xem các câu trả lời khác.
Để sử dụng looping, hãy lấy tất cả các đối số và theo 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_!" && for /l %%l in (!_cnt! 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_!"
)
fake-command /u !_arg_[1]! /p !_arg_[2]! > test-log.txt
?*&<>