Comment puis-je transmettre des arguments à un fichier batch ?
-
09-06-2019 - |
Question
Je dois transmettre un identifiant et un mot de passe à un fichier de commandes au moment de son exécution plutôt que de les coder en dur dans le fichier.
Voici à quoi ressemble la ligne de commande :
test.cmd admin P@55w0rd > test-log.txt
La solution 2
Voici comment j'ai procédé :
@fake-command /u %1 /p %2
Voici à quoi ressemble la commande :
test.cmd admin P@55w0rd > test-log.txt
Le %1
s'applique au premier paramètre le %2
(et voici la partie délicate) s'applique à la seconde.Vous pouvez transmettre jusqu'à 9 paramètres de cette manière.
Autres conseils
Un autre conseil utile est d'utiliser %*
pour signifier « tout ».Par exemple:
echo off
set arg1=%1
set arg2=%2
shift
shift
fake-command /u %arg1% /p %arg2% %*
Quand vous courez :
test-command admin password foo bar
le fichier batch ci-dessus s'exécutera :
fake-command /u admin /p password admin password foo bar
J'ai peut-être une syntaxe légèrement erronée, mais c'est l'idée générale.
Si vous souhaitez gérer intelligemment les paramètres manquants, vous pouvez faire quelque chose comme :
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'accès aux paramètres du lot peut être simple avec %1, %2, ...%9 ou encore %*,
mais seulement si le contenu est simple.
Il n'existe pas de moyen simple pour des contenus complexes comme "&"^&
, car il n'est pas possible d'accéder à %1 sans produire une erreur.
set var=%1
set "var=%1"
set var=%~1
set "var=%~1"
Les lignes s'étendent jusqu'à
set var="&"&
set "var="&"&"
set var="&"&
set "var="&"&"
Et chaque ligne échoue, comme l'un des &
est en dehors des guillemets.
Cela peut être résolu en lisant à partir d'un fichier temporaire un remarqué version du paramètre.
@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!'
L'astuce consiste à activer echo on
et développez le %1 après un rem
déclaration (fonctionne également avec %2 .. %*
).
Alors même "&"&
pourrait être repris sans produire d’erreur, comme on le remarque.
Mais pour pouvoir rediriger la sortie du echo on
, vous avez besoin des deux boucles for.
Les personnages supplémentaires * #
sont utilisés pour être en sécurité contre des contenus comme /?
(montrerait l'aide pour REM
).
Ou un caret ^ à la fin de la ligne pourrait fonctionner comme un caractère multiligne, même après un rem
.
Puis en lisant le paramètre rem sortie du fichier, mais avec précaution.
Le For / F devrait fonctionner avec une expansion retardée, sinon le contenu de "!" serait détruit.
Après avoir supprimé les caractères supplémentaires dans param1
, tu l'as eu.
Et pour utiliser param1
de manière sûre, permettre l'expansion retardée.
Oui, et n'oubliez pas d'utiliser des variables comme %%1
lors de l'utilisation if
et for
et la bande.
Si tu oublies le double %
, vous remplacerez alors les arguments de ligne de commande (éventuellement nuls) et vous recevrez des messages d'erreur assez déroutants.
Il n’est pas nécessaire de compliquer les choses.Il s'agit simplement de la commande %1 %2 paramètres, par exemple,
@echo off
xcopy %1 %2 /D /E /C /Q /H /R /K /Y /Z
echo copied %1 to %2
pause
La "pause" affiche ce que le fichier batch a fait et attend que vous appuyiez sur la touche ANY.Enregistrez-le sous xx.bat dans le dossier Windows.
Pour l'utiliser, tapez par exemple :
xx c:\f\30\*.* f:\sites\30
Ce fichier batch prend en charge tous les paramètres nécessaires, comme la copie uniquement des fichiers, les plus récents, etc.Je l'utilise depuis avant Windows.Si vous aimez voir les noms des fichiers au fur et à mesure de leur copie, laissez de côté le Q
paramètre.
@ECHO OFF
:Loop
IF "%1"=="" GOTO Continue
SHIFT
GOTO Loop
:Continue
Note:SI "%1"==""
causera des problèmes si %1
est lui-même entouré de guillemets.
Dans ce cas, utilisez IF [%1]==[]
ou, dans NT 4 (SP6) et versions ultérieures uniquement, IF "%~1"==""
plutôt.
Un ami m'a récemment posé des questions sur ce sujet, alors j'ai pensé publier comment je gère les arguments de ligne de commande dans les fichiers batch.
Cette technique entraîne un peu de surcharge, comme vous le verrez, mais elle rend mes fichiers batch très faciles à comprendre et rapides à mettre en œuvre.En plus de soutenir les structures suivantes :
>template.bat [-f] [--flag] [/f] [--namedvalue value] arg1 [arg2][arg3][...]
L'essentiel, c'est d'avoir le :init
, :parse
, et :main
les fonctions.
Exemple d'utilisation
>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"
modèle.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
Gardons cela simple.
Voici le fichier .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%
Voici 3 appels depuis la ligne de commande.
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
)
Cela boucle sur les paramètres du lot (%*), qu'ils soient cités ou non, puis fait écho à chaque paramètre.
J'ai écrit un simple script read_params qui peut être appelé en tant que fonction (ou externe). .bat
) et mettra toutes les variables dans l'environnement actuel.Cela ne modifiera pas les paramètres d'origine car la fonction est en cours call
accompagné d'une copie des paramètres d'origine.
Par exemple, étant donné la commande suivante :
myscript.bat some -random=43 extra -greeting="hello world" fluff
myscript.bat
serait capable d'utiliser les variables après avoir appelé la fonction :
call :read_params %*
echo %random%
echo %greeting%
Voici la fonction :
: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
Limites
- Impossible de charger des arguments sans valeur tels que
-force
.Vous pourriez utiliser-force=true
mais je ne vois pas de moyen d'autoriser des valeurs vides sans connaître à l'avance une liste de paramètres qui n'auront pas de valeur.
Journal des modifications
- 2/18/2016
- Ne nécessite plus d'expansion retardée
- Fonctionne désormais avec d'autres arguments de ligne de commande en recherchant
-
avant les paramètres.
Pour faire référence à une variable définie en ligne de commande, vous devrez utiliser %a%
donc par exemple :
set a=100
echo %a%
rem output = 100
Note:Cela fonctionne pour Windows 7 professionnel.
Créez un nouveau fichier batch (exemple :openclass.bat) et écrivez cette ligne dans le fichier :
java %~n1
Placez ensuite le fichier batch dans, disons, le dossier system32, allez dans votre fichier de classe Java, faites un clic droit, Propriétés, Ouvrir avec..., puis trouvez votre fichier batch, sélectionnez-le et c'est tout...
Ça marche pour moi.
PS :Je ne trouve pas de moyen de fermer la fenêtre cmd lorsque je ferme la classe Java.Pour l'instant...
Inspiré par un réponse ailleurs par @Jon, j'ai conçu un algorithme plus général pour extraire les paramètres nommés, les valeurs facultatives et les commutateurs.
Disons que nous voulons implémenter un utilitaire foobar
.Cela nécessite une commande initiale.Il a un paramètre facultatif --foo
ce qui prend un facultatif valeur (qui ne peut pas être un autre paramètre, bien sûr) ;si la valeur est manquante, la valeur par défaut est default
.Il possède également un paramètre facultatif --bar
ce qui prend un requis valeur.Enfin, il peut prendre un drapeau --baz
sans aucune valeur autorisée.Oh, et ces paramètres peuvent venir dans n’importe quel ordre.
En d'autres termes, cela ressemble à ceci :
foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]
Voici une solution :
@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
- Utiliser
SETLOCAL
afin que les variables ne s'échappent pas dans l'environnement appelant. - N'oubliez pas d'initialiser les variables
SET FOO=
, etc.au cas où quelqu'un les définirait dans l'environnement appelant. - Utiliser
%~1
pour supprimer les guillemets. - Utiliser
IF "%ARG%" == ""
et pasIF [%ARG%] == []
parce que[
et]
ne jouez pas du tout à will avec des valeurs se terminant par un espace. - Même si vous
SHIFT
à l'intérieur d'unIF
bloc, les arguments actuels tels que%~1
ne sont pas mis à jour car ils sont déterminés lorsque leIF
est analysé.Vous pourriez utiliser%~1
et%~2
à l'intérieur deIF
bloquer, mais ce serait déroutant car vous aviez unSHIFT
.Tu pourrais mettre leSHIFT
à la fin du bloc pour plus de clarté, mais cela pourrait également se perdre et/ou dérouter les gens.Donc "capturer"%~1
et%~1
en dehors du pâté de maisons semble le mieux. - Vous ne souhaitez pas utiliser un paramètre à la place de la valeur facultative d'un autre paramètre, vous devez donc vérifier
IF NOT "%ARG:~0,2%" == "--"
. - Faites attention seulement à
SHIFT
lorsque vous utiliser un des paramètres. - Le code en double
SET FOO=%DEFAULT_FOO%
est regrettable, mais l'alternative serait d'ajouter unIF "%FOO%" == "" SET FOO=%DEFAULT_FOO%
en dehors deIF NOT "%ARG%" == ""
bloc.Cependant, comme c'est toujours à l'intérieur duIF "%PARAM%" == "--foo"
bloquer, le%FOO%
la valeur aurait été évaluée et définie avant que vous n'entriez dans le bloc, vous ne le détecteriez donc jamais les deux le--foo
le paramètre était présent et aussi que le%FOO%
la valeur manquait. - Noter que
ECHO Missing bar value. 1>&2
envoie le message d'erreur à stderr. - Vous voulez une ligne vide dans un fichier batch Windows ?Tu dois utiliser
ECHO:
ou l'une des variantes.
Solution simple (même si la question est ancienne)
Test1.bat
echo off
echo "Batch started"
set arg1=%1
echo "arg1 is %arg1%"
echo on
pause
AppelTest1.bat
call "C:\Temp\Test1.bat" pass123
sortir
YourLocalPath>call "C:\Temp\test.bat" pass123
YourLocalPath>echo off
"Batch started"
"arg1 is pass123"
YourLocalPath>pause
Press any key to continue . . .
Où YourLocalPath est le chemin du répertoire actuel.
Pour garder les choses simples, stockez le paramètre de commande dans une variable et utilisez la variable à des fins de comparaison.
Ce n'est pas seulement simple à écrire, mais c'est aussi simple à maintenir, donc si plus tard une autre personne ou vous lisez votre script après une longue période, il sera facile à comprendre et à maintenir.
Pour écrire du code en ligne :voir d'autres réponses.
Pour utiliser le bouclage, récupérez tous les arguments et en pur batch :
@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
Votre code est prêt à faire quelque chose avec le numéro d'argument là où il en a besoin, comme...
@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