web-dev-qa-db-fra.com

Fichiers batch - nombre d'arguments en ligne de commande

Il suffit de convertir certains scripts Shell en fichiers de commandes et il y a une chose que je n'arrive pas à trouver ... et c'est un simple décompte du nombre d'arguments en ligne de commande.

par exemple. si tu as:

myapp foo bar

En coquille:

  • $ # -> 2
  • $ * -> foo bar
  • $ 0 -> myapp
  • 1 $ -> foo
  • 2 $ -> bar

En lot

  • ?? -> 2 <---- quelle commande?!
  • % * -> foo bar
  • % 0 -> myapp
  • % 1 -> toto
  • % 2 -> bar

J'ai donc regardé autour de moi, soit je suis au mauvais endroit, soit je suis aveugle, mais je n'arrive pas à trouver le moyen d'obtenir un nombre de arguments en ligne de commande passés.

Existe-t-il une commande similaire à "$ #" de Shell pour les fichiers de traitement par lots?

ps. le plus proche que j'ai trouvé est de parcourir les% 1 et d'utiliser 'shift', mais j'ai besoin de refernece% 1,% 2, etc. plus tard dans le script, donc ce n'est pas bon.

86
pyko

Googling un peu vous donne le résultat suivant de wikibooks :

set argC=0
for %%x in (%*) do Set /A argC+=1

echo %argC%

On dirait que cmd.exe a un peu évolué depuis les anciens jours du DOS :)

92
nimrodm

Vous avez tendance à gérer plusieurs arguments avec ce type de logique:

IF "%1"=="" GOTO HAVE_0
IF "%2"=="" GOTO HAVE_1
IF "%3"=="" GOTO HAVE_2

etc.

Si vous avez plus de 9 arguments, cette approche vous trompe. Il existe différents hacks pour la création de compteurs que vous pouvez trouver ici , mais sachez que ce ne sont pas pour les âmes sensibles.

39
Dean Povey

La fonction :getargc ci-dessous est peut-être ce que vous cherchez.

@echo off
setlocal enableextensions enabledelayedexpansion
call :getargc argc %*
echo Count is %argc%
echo Args are %*
endlocal
goto :eof

:getargc
    set getargc_v0=%1
    set /a "%getargc_v0% = 0"
:getargc_l0
    if not x%2x==xx (
        shift
        set /a "%getargc_v0% = %getargc_v0% + 1"
        goto :getargc_l0
    )
    set getargc_v0=
    goto :eof

En gros, il effectue une itération une fois sur la liste (qui est locale à la fonction pour que les décalages n’affectent pas la liste dans le programme principal), en les comptant jusqu’à épuisement.

Il utilise également une astuce astucieuse, en passant le nom de la variable de retour à définir par la fonction.

Le programme principal illustre simplement comment l'appeler et fait ensuite écho aux arguments pour s'assurer qu'ils ne sont pas touchés:

C:\Here> xx.cmd 1 2 3 4 5
    Count is 5
    Args are 1 2 3 4 5
C:\Here> xx.cmd 1 2 3 4 5 6 7 8 9 10 11
    Count is 11
    Args are 1 2 3 4 5 6 7 8 9 10 11
C:\Here> xx.cmd 1
    Count is 1
    Args are 1
C:\Here> xx.cmd
    Count is 0
    Args are
C:\Here> xx.cmd 1 2 "3 4 5"
    Count is 3
    Args are 1 2 "3 4 5"
18
paxdiablo

Si le nombre d'arguments doit être un nombre exact (inférieur ou égal à 9), il s'agit d'un moyen simple de le vérifier:

if "%2" == "" goto args_count_wrong
if "%3" == "" goto args_count_ok

:args_count_wrong
echo I need exactly two command line arguments
exit /b 1

:args_count_ok
6
slu

Essaye ça:

SET /A ARGS_COUNT=0    
FOR %%A in (%*) DO SET /A ARGS_COUNT+=1    
ECHO %ARGS_COUNT%
6
David

Évite d’utiliser shift ou un cycle for au détriment de la taille et de la lisibilité.

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set /a arg_idx=1
set "curr_arg_value="
:loop1
if !arg_idx! GTR 9 goto :done
set curr_arg_label=%%!arg_idx!
call :get_value curr_arg_value !curr_arg_label!
if defined curr_arg_value (
  echo/!curr_arg_label!: !curr_arg_value!
  set /a arg_idx+=1
  goto :loop1
)
:done
set /a cnt=!arg_idx!-1
echo/argument count: !cnt!
endlocal
goto :eof

:get_value
(
  set %1=%2
)

Sortie:

count_cmdline_args.bat testing more_testing arg3 another_arg

%1: testing
%2: more_testing
%3: arg3
%4: another_arg
argument count: 4

EDIT: Le "truc" utilisé ici implique:

  1. Construire une chaîne qui représente une variable d’argument de ligne de commande actuellement évaluée ("% 1", "% 2", etc.) à l’aide d’une chaîne contenant un caractère de pourcentage (%%) et une variable de compteur arg_idx à chaque itération de la boucle.

  2. Stocker cette chaîne dans une variable curr_arg_label.

  3. Passer cette chaîne (!curr_arg_label!) et un nom de variable de retour (curr_arg_value) à un sous-programme primitif get_value.

  4. Dans le sous-programme, son premier argument (%1) valeur est utilisée du côté gauche de l'affectation (set) et de son second argument (%2) valeur à droite. Cependant, lorsque l'argument du second sous-programme est passé, il est résolu en valeur de l'argument de ligne de commande du programme principal par l'interpréteur de commandes. Autrement dit, ce qui est passé n'est pas, par exemple, "% 4" mais quelle que soit la valeur retenue par la quatrième variable d'argument de ligne de commande ("another_arg" dans l'exemple d'utilisation).

  5. Ensuite, la variable donnée au sous-programme en tant que variable de retour (curr_arg_value) est testé pour être indéfini, ce qui se produirait si l’argument de ligne de commande actuellement évalué est absent. Initialement, il s'agissait d'une comparaison de la valeur de la variable de retour entourée de crochets vides (ce qui est le seul moyen que je connaisse des arguments de programme de test ou de sous-programme pouvant contenir des guillemets et constituant un reliquat négligé de la phase d'essais et erreurs), mais a depuis été fixée à la situation actuelle.

2
fen-fire

La dernière réponse datait d'il y a deux ans, mais j'avais besoin d'une version pour plus de neuf arguments en ligne de commande. Peut-être un autre fait aussi ...

@echo off
setlocal

set argc_=1
set arg0_=%0
set argv_=

:_LOOP
set arg_=%1
if defined arg_ (
  set arg%argc_%_=%1
  set argv_=%argv_% %1
  set /a argc_+=1
  shift
  goto _LOOP
)
::dont count arg0
set /a argc_-=1
echo %argc_% arg(s)

for /L %%i in (0,1,%argc_%) do (
  call :_SHOW_ARG arg%%i_ %%arg%%i_%%
)

echo converted to local args
call :_LIST_ARGS %argv_%
exit /b


:_LIST_ARGS
setlocal
set argc_=0
echo arg0=%0

:_LOOP_LIST_ARGS
set arg_=%1
if not defined arg_ exit /b
set /a argc_+=1
call :_SHOW_ARG arg%argc_% %1
shift
goto _LOOP_LIST_ARGS


:_SHOW_ARG
echo %1=%2
exit /b

La solution est constituée des 19 premières lignes et convertit tous les arguments en variables dans un style similaire à celui de c. Tous les autres éléments ne font que sonder le résultat et montrer la conversion en arguments locaux. Vous pouvez référencer des arguments par index dans n’importe quelle fonction.

1
Kasimir