Come posso passare argomenti a un file batch?
-
09-06-2019 - |
Domanda
Devo passare un ID e una password a un file batch al momento dell'esecuzione anziché codificarli nel file.
Ecco come appare la riga di comando:
test.cmd admin P@55w0rd > test-log.txt
Soluzione 2
Ecco come l'ho fatto:
@fake-command /u %1 /p %2
Ecco come appare il comando:
test.cmd admin P@55w0rd > test-log.txt
IL %1
si applica al primo parametro il %2
(e qui sta la parte difficile) si applica al secondo.In questo modo è possibile passare fino a 9 parametri.
Altri suggerimenti
Un altro consiglio utile è usare %*
significare "tutti".Per esempio:
echo off
set arg1=%1
set arg2=%2
shift
shift
fake-command /u %arg1% /p %arg2% %*
Quando corri:
test-command admin password foo bar
verrà eseguito il file batch sopra:
fake-command /u admin /p password admin password foo bar
Potrei avere la sintassi leggermente sbagliata, ma questa è l'idea generale.
Se vuoi gestire in modo intelligente i parametri mancanti puoi fare qualcosa del tipo:
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
L'accesso ai parametri batch può essere semplice con %1, %2, ...%9 o anche %*,
ma solo se il contenuto è semplice.
Non esiste un modo semplice per contenuti complessi come "&"^&
, poiché non è possibile accedere a %1 senza produrre un errore.
set var=%1
set "var=%1"
set var=%~1
set "var=%~1"
Le linee si espandono in
set var="&"&
set "var="&"&"
set var="&"&
set "var="&"&"
E ogni riga fallisce, come una delle &
è fuori dalle virgolette.
Può essere risolto leggendo da un file temporaneo a ha osservato versione del parametro.
@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!'
Il trucco è abilitare echo on
ed espandere %1 dopo a rem
dichiarazione (funziona anche con %2 .. %*
).
Quindi anche "&"&
potrebbe essere ripetuto senza produrre un errore, come viene osservato.
Ma per essere in grado di reindirizzare l'output di echo on
, sono necessari i due cicli for.
I personaggi extra * #
sono usati per essere sicuri contro contenuti come /?
(mostrerebbe l'aiuto per REM
).
Oppure un accento circonflesso ^ alla fine della riga potrebbe funzionare come carattere su più righe, anche dopo a rem
.
Poi leggendo il parametro rem output dal file, ma con attenzione.
Il per /f dovrebbe funzionare con l'espansione ritardata, altrimenti con "!" sarebbe distrutto.
Dopo aver rimosso i caratteri extra in param1
, avete capito bene.
E da usare param1
in modo sicuro, abilitare l'espansione ritardata.
Sì, e non dimenticare di usare variabili come %%1
quando si usa if
E for
e la banda.
Se dimentichi il doppio %
, allora sostituirai gli argomenti della riga di comando (possibilmente null) e riceverai alcuni messaggi di errore piuttosto confusi.
Non è necessario complicarlo.È semplicemente il comando %1 %2 parametri, ad esempio,
@echo off
xcopy %1 %2 /D /E /C /Q /H /R /K /Y /Z
echo copied %1 to %2
pause
La "pausa" mostra ciò che ha fatto il file batch e attende che tu prema il tasto QUALSIASI.Salvalo come xx.bat nella cartella Windows.
Per utilizzarlo digitare, ad esempio:
xx c:\f\30\*.* f:\sites\30
Questo file batch si occupa di tutti i parametri necessari, come copiare solo i file, quelli più recenti, ecc.Lo uso da prima di Windows.Se ti piace vedere i nomi dei file mentre vengono copiati, tralascia il file Q
parametro.
@ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue
Nota:SE "%1"==""
causerà problemi se %1
è racchiuso tra virgolette.
In tal caso, utilizzare IF [%1]==[]
oppure, solo in NT 4 (SP6) e versioni successive, IF "%~1"==""
Invece.
Recentemente un amico mi ha chiesto informazioni su questo argomento, quindi ho pensato di pubblicare come gestisco gli argomenti della riga di comando nei file batch.
Come vedrai, questa tecnica comporta un po' di sovraccarico, ma rende i miei file batch molto facili da comprendere e rapidi da implementare.Oltre a supportare le seguenti strutture:
>template.bat [-f] [--flag] [/f] [--namedvalue value] arg1 [arg2][arg3][...]
Il succo è avere il :init
, :parse
, E :main
funzioni.
Utilizzo di esempio
>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"
modello.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
Manteniamolo semplice.
Ecco il file .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%
Ecco 3 chiamate dalla riga di comando.
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
)
Questo esegue il loop sui parametri batch (%*) che siano tra virgolette o meno, quindi visualizza ciascun parametro.
Ho scritto un semplice script read_params che può essere chiamato come funzione (o external .bat
) e inserirà tutte le variabili nell'ambiente corrente.Non modificherà i parametri originali perché la funzione è in corso call
ed con una copia dei parametri originali.
Ad esempio, dato il seguente comando:
myscript.bat some -random=43 extra -greeting="hello world" fluff
myscript.bat
sarebbe in grado di utilizzare le variabili dopo aver chiamato la funzione:
call :read_params %*
echo %random%
echo %greeting%
Ecco la funzione:
: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
Limitazioni
- Impossibile caricare argomenti senza valore come
-force
.Potresti usare-force=true
ma non riesco a pensare a un modo per consentire valori vuoti senza conoscere in anticipo un elenco di parametri che non avranno un valore.
Registro delle modifiche
- 2/18/2016
- Non richiede più un'espansione ritardata
- Ora funziona con altri argomenti della riga di comando cercando
-
prima dei parametri.
Per fare riferimento a una variabile impostata nella riga di comando è necessario utilizzare %a%
quindi ad esempio:
set a=100
echo %a%
rem output = 100
Nota:Funziona con Windows 7 pro.
Crea un nuovo file batch (esempio:openclass.bat) e scrivere questa riga nel file:
java %~n1
Quindi posiziona il file batch, diciamo, nella cartella system32, vai al file della classe Java, fai clic con il pulsante destro del mouse, Proprietà, Apri con..., quindi trova il file batch, selezionalo e il gioco è fatto...
Per me funziona.
PS:Non riesco a trovare un modo per chiudere la finestra cmd quando chiudo la classe Java.Per adesso...
Ispirato da un rispondere altrove di @Jon, ho creato un algoritmo più generale per estrarre parametri denominati, valori opzionali e opzioni.
Diciamo che vogliamo implementare un'utilità foobar
.Richiede un comando iniziale.Ha un parametro facoltativo --foo
che richiede un opzionale valore (che ovviamente non può essere un altro parametro);se manca il valore, il valore predefinito è default
.Ha anche un parametro opzionale --bar
che richiede a necessario valore.Infine può prendere una bandiera --baz
senza valore consentito.Oh, e questi parametri possono essere presenti in qualsiasi ordine.
In altre parole, assomiglia a questo:
foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]
Ecco una soluzione:
@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
- Utilizzo
SETLOCAL
in modo che le variabili non fuoriescano nell'ambiente chiamante. - Non dimenticare di inizializzare le variabili
SET FOO=
, eccetera.nel caso qualcuno li definisse nell'ambiente chiamante. - Utilizzo
%~1
per rimuovere le virgolette. - Utilizzo
IF "%ARG%" == ""
e nonIF [%ARG%] == []
Perché[
E]
non riprodurre affatto will con valori che terminano con uno spazio. - Anche se tu
SHIFT
all'interno di unIF
blocco, gli argomenti attuali come%~1
non vengono aggiornati perché vengono determinati quando il fileIF
viene analizzato.Potresti usare%~1
E%~2
dentro ilIF
blocco, ma creerebbe confusione perché avevi un fileSHIFT
.Potresti mettere ilSHIFT
alla fine del blocco per chiarezza, ma anche questo potrebbe perdersi e/o confondere le persone.Quindi "catturare"%~1
E%~1
fuori dal blocco sembra migliore. - Non vuoi utilizzare un parametro al posto del valore facoltativo di un altro parametro, quindi devi controllare
IF NOT "%ARG:~0,2%" == "--"
. - Fai attenzione solo a
SHIFT
quando tu utilizzo uno dei parametri. - Il codice duplicato
SET FOO=%DEFAULT_FOO%
è deplorevole, ma l'alternativa sarebbe aggiungere unIF "%FOO%" == "" SET FOO=%DEFAULT_FOO%
fuori daIF NOT "%ARG%" == ""
bloccare.Tuttavia poiché questo è ancora all'interno del fileIF "%PARAM%" == "--foo"
blocco, il%FOO%
value sarebbe stato valutato e impostato prima che tu entrassi nel blocco, quindi non lo rileveresti mai Entrambi IL--foo
il parametro era presente e anche che il%FOO%
mancava il valore. - Notare che
ECHO Missing bar value. 1>&2
invia il messaggio di errore a stderr. - Vuoi una riga vuota in un file batch di Windows?Devi usare
ECHO:
o una delle varianti.
Soluzione semplice (anche se la domanda è vecchia)
Prova1.bat
echo off
echo "Batch started"
set arg1=%1
echo "arg1 is %arg1%"
echo on
pause
ChiamaTest1.bat
call "C:\Temp\Test1.bat" pass123
produzione
YourLocalPath>call "C:\Temp\test.bat" pass123
YourLocalPath>echo off
"Batch started"
"arg1 is pass123"
YourLocalPath>pause
Press any key to continue . . .
Dove YourLocalPath è il percorso della directory corrente.
Per semplificare le cose, memorizza il comando param nella variabile e usa la variabile per il confronto.
Non è solo semplice da scrivere, ma è anche semplice da mantenere, quindi se in seguito qualcun altro o tu leggessi la tua sceneggiatura dopo un lungo periodo di tempo, sarà facile da capire e mantenere.
Per scrivere il codice in linea:vedi altre risposte.
Per utilizzare il loop ottieni tutti gli argomenti e in batch puro:
@echo off && setlocal EnableDelayedExpansion
set "_cnt=0" && for %%Z in (%*) do (
set "_arg_=%%Z" && set /a "_cnt=!_cnt! + 1" && set "_arg_[!_cnt!]=!_arg_!"
shift && for /l %%l in (!_cnt! 1 !_cnt!) do echo/ The argument n:%%l is: !_arg_[%%l]!
)
goto :eof
Il tuo codice è pronto per fare qualcosa con il numero di argomento dove necessario, come...
@echo off && setlocal EnableDelayedExpansion
set "_cnt=0" && for %%Z in (%*) do (
set "_arg_=%%Z" && set /a "_cnt=!_cnt! + 1" && set "_arg_[!_cnt!]=!_arg_!"
shift
)
fake-command /u !_arg_[1]! /p !_arg_[2]! > test-log.txt