windows :~ - Come posso passare i parametri della riga di comando a un file batch?




command commands (13)

Devo passare id e password a un file cmd (o bat) al momento dell'esecuzione piuttosto che codificarli nel file.

Ecco come appare la riga di comando:

test.cmd admin [email protected] > test-log.txt

Answers

Non c'è bisogno di complicarlo. È semplicemente 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 il file batch ha fatto e aspetta che tu prenda il tasto ANY. Salvalo come xx.bat nella cartella di Windows.

Per usarlo, digitare, ad esempio:

xx c:\f\30\*.* f:\sites\30

Questo file batch si prende cura di tutti i parametri necessari, come copiare solo i file, che sono più recenti, ecc. L'ho usato da prima di Windows. Se ti piace vedere i nomi dei file, mentre vengono copiati, lascia fuori il parametro Q


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 dei parametri batch (% *) o sono quotati o meno, quindi esegue l'eco di ciascun parametro.


Ecco come lo faccio.

@fake-command /u %1 /p %2

Ecco come appare la riga di comando:

test.cmd admin [email protected] > test-log.txt

Il% 1 si applica al primo parametro il% 2 (e qui è la parte difficile) si applica al secondo. Puoi avere fino a 9 parametri passati in questo modo.


Manteniamo questo 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%

Qui ci sono 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>

Un amico mi stava chiedendo di questo argomento di recente, quindi ho pensato di pubblicare come gestisco gli argomenti della riga di comando nei file batch.

Questa tecnica ha un po 'di overhead come vedrai, ma rende i miei file batch molto facili da capire e veloci da implementare. Oltre a supportare le seguenti strutture:

>template.bat [-f] [--flag] [/f] [--namedvalue value] arg1 [arg2][arg3][...]

Il suo jist sta avendo :init ,: :parse e :main funzioni :main .

Esempio di utilizzo

>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

Ispirato da una risposta altrove @Jon, ho creato un algoritmo più generale per l'estrazione di parametri denominati, valori opzionali e opzioni.

Diciamo che vogliamo implementare una utility foobar . Richiede un comando iniziale. Ha un parametro opzionale --foo che accetta un valore opzionale (che non può essere un altro parametro, ovviamente); se il valore è mancante, il valore predefinito è default . Ha anche un parametro opzionale --bar che accetta un valore richiesto . Infine può prendere una bandiera --baz senza valore consentito. Oh, e questi parametri possono venire 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
  • Utilizzare SETLOCAL modo che le variabili non sfuggano nell'ambiente chiamante.
  • Non dimenticare di inizializzare le variabili SET FOO= , ecc. Nel caso qualcuno le definisse nell'ambiente di chiamata.
  • Usa %~1 per rimuovere le virgolette.
  • Usa IF "%ARG%" == "" e non IF [%ARG%] == [] perché [ e ] non esegui affatto con valori che terminano in uno spazio.
  • Anche se si SHIFT all'interno di un blocco IF , gli argomenti correnti come %~1 non vengono aggiornati perché vengono determinati quando viene analizzata l' IF . Potresti usare %~1 e %~2 all'interno del blocco IF , ma sarebbe fonte di confusione perché avevi uno SHIFT . Puoi mettere lo SHIFT alla fine del blocco per chiarezza, ma questo potrebbe perdersi e / o confondere anche le persone. Quindi "catturare" %~1 e %~1 al di fuori del blocco sembra il migliore.
  • Non si desidera utilizzare un parametro al posto del valore facoltativo di un altro parametro, quindi è necessario selezionare IF NOT "%ARG:~0,2%" == "--" .
  • Prestare attenzione solo a SHIFT quando si utilizza uno dei parametri.
  • Il codice duplicato SET FOO=%DEFAULT_FOO% è deplorevole, ma l'alternativa sarebbe aggiungere un IF "%FOO%" == "" SET FOO=%DEFAULT_FOO% al di fuori del blocco IF NOT "%ARG%" == "" block . Tuttavia, poiché questo è ancora all'interno del blocco IF "%PARAM%" == "--foo" , il valore %FOO% sarebbe stato valutato e impostato prima di essere inserito nel blocco, in modo da non rilevare mai che entrambi --foo era presente il parametro --foo e inoltre mancava il valore %FOO% .
  • Notare che il ECHO Missing bar value. 1>&2 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.

Ho scritto un semplice script read_params che può essere chiamato come funzione (o .bat esterno) e inserirà tutte le variabili nell'ambiente corrente. Non modificherà i parametri originali perché la funzione viene call 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 . È possibile utilizzare -force=true ma non riesco a pensare a un modo per consentire valori vuoti senza conoscere un elenco di parametri prima del tempo che non avrà un valore.

changelog

  • 2016/02/18
    • Non richiede più un'espansione ritardata
    • Ora funziona con altri argomenti della riga di comando cercando prima i parametri.

Sì, e non dimenticare di usare variabili come %%1 quando usi if e for e la gang.

Se si dimentica il doppio % , allora si sostituiranno gli argomenti (eventualmente nulli) della riga di comando e si riceveranno alcuni messaggi di errore piuttosto confusi.


Un altro suggerimento utile è usare %* per indicare "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

il file batch sopra indicato verrà eseguito:

fake-command /u admin /p password foo bar

Potrei avere la sintassi leggermente sbagliata, ma questa è l'idea generale.


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 generare 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 linea fallisce, in quanto uno dei & è al di fuori delle virgolette.

Può essere risolto leggendo da un file temporaneo una versione notificata 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 un'istruzione rem (funziona anche con %2 .. %* ).
Quindi anche "&"& potrebbe essere echeggiato senza produrre un errore, come viene osservato.

Ma per essere in grado di reindirizzare l'output echo on , sono necessari i due "loop".

I caratteri extra * # sono usati per essere sicuri contro contenuti come /? (mostrerebbe l'aiuto per REM ).
Oppure un segno di omissione ^ alla fine della linea potrebbe funzionare come un carattere multilinea, anche dopo un rem .

Quindi leggendo l'output del parametro rem dal file, ma con attenzione.
Il FOR / F dovrebbe funzionare con l'espansione ritardata disattivata, altrimenti i contenuti con "!" sarebbe distrutto
Dopo aver rimosso i caratteri extra in param1 , hai capito.

E per usare param1 in modo sicuro, abilitare l'espansione ritardata.


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

@ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue

Nota: IF "%1"=="" causerà problemi se %1 è racchiuso tra virgolette stesse.

In tal caso, utilizzare IF [%1]==[] o, in NT 4 (SP6) e solo successivamente, IF "%~1"=="" .


Alcuni potrebbero trovare questo utile. Valori interi in sostituzione variabile, in cui il trucco utilizza parentesi quadre $(()) :

N=3
M=3
COUNT=$N-1
ARR[0]=3
ARR[1]=2
ARR[2]=4
ARR[3]=1

while (( COUNT < ${#ARR[@]} ))
do
  ARR[$COUNT]=$((ARR[COUNT]*M))
  (( COUNT=$COUNT+$N ))
done




windows batch-file command-line cmd