2009-08-18 13 views
77

Simplemente convierto algunos scripts de shell en archivos por lotes y hay una cosa que parece que no puedo encontrar ... y es un conteo simple del número de argumentos de línea de comando.Archivos de proceso por lotes: número de argumentos de línea de comando

por ejemplo. si tiene:

myapp foo bar 

En Shell:

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

en lote

  • ?? -> 2 < ---- ¿qué comando ?!
  • % * -> foo bar
  • % 0 -> miaplicacion
  • % 1 -> foo
  • % 2 -> Barra de

Así que he mirado alrededor, y ya sea que Estoy buscando en el lugar equivocado o estoy ciego, pero parece que no puedo encontrar una manera de contar el número de argumentos de línea de comando pasados.

¿Hay algún comando similar al "$ # de shell? "para los archivos por lotes?

ps. Lo más parecido que he encontrado es recorrer el% 1s y usar 'shift', pero necesito referirme a% 1,% 2, etc. más adelante en el script, así que eso no es bueno.

+0

su cadena es '2 myapp foo bar'? – PsychoData

+2

consejo: no convierta sh en BAT. , en su lugar, descargue cygwin y úselo. es decir, sus scripts sh funcionarán en una máquina de Windows. ¡y no tendrás que traducir cada sh a BAT! –

Respuesta

81

googlear un poco le da el siguiente resultado de wikibooks:

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

echo %argC% 

Parece que cmd.exe ha evolucionado un poco desde los viejos días de DOS :)

+7

Tenga en cuenta que esta variante de 'for' solo funciona para argumentos que parecen nombres de archivo, no cadenas de opciones como' -? '. El uso de comillas ('para %% i in ("% * ") ...') funciona para argumentos como '-?' Pero nuevamente falla para los argumentos entrecomillados debido a las comillas anidadas. La única forma robusta parece involucrar 'shift' ... –

+1

lo siento, downvoted por lo que @FerdinandBeyer dice – n611x007

33

usted tiende a manejar varios argumentos con este tipo de lógica:

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

etc.

Si usted tiene más de 9 argumentos a continuación, se atornillan con este enfoque sin embargo. Hay varios hacks para crear contadores que puedes encontrar en here, pero ten en cuenta que estos no son para cardíacos.

+3

Aún puede usar 'shift' para contar más de 9 ...y sin tener 10 líneas de código con la misma apariencia. – Joey

18

La función :getargc a continuación puede ser lo que estás buscando.

@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 

Básicamente repite una vez más de la lista (que es local a la función por lo que los cambios no afectarán a la lista de nuevo en el programa principal), contando ellos hasta que se agote.

También utiliza un ingenioso truco, pasando el nombre de la variable de retorno que establecerá la función.

El programa principal, justo ilustra cómo llamar a él y hace eco de los argumentos después para asegurarse de que están intactos:

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" 
+0

¿cómo se puede alterar el flujo en función de esto? (Puede ser una pregunta diferente, pero creo que un pequeño ejemplo también sería muy conveniente aquí) – n611x007

+0

@ n611x007 donde el 'echo Count es% argc%' insertarías tu propio código que podría verificar si ese conteo es correcto y luego siga adelante. – kenny

6

Prueba esto:

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

es esta respuesta de alguna manera diferente de [@nimrod one] (http://stackoverflow.com/a/1292094/505893) ? ... – bluish

+0

ver el comentario de @FerdinandBeyer en nimrodm's. no va a vencer porque tiene 21 rep 8) – n611x007

5

Si el número de argumentos debe ser un número exacto (menor o igual a 9), entonces esta es una manera simple de comprobar que:

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 
2

evita el uso de ya sea shift o un ciclo for en el costo de tamaño y legibilidad.

@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 
) 

Salida:

count_cmdline_args.bat testing more_testing arg3 another_arg 

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

EDIT: El "truco" utilizado aquí se refiere a:

  1. La construcción de una cadena que representa una variable de argumentos de línea de comandos actualmente evaluado (es decir, "% 1 ","% 2 ", etc.) utilizando una cadena que contiene un carácter de porcentaje (%%) y una variable de contador arg_idx en cada iteración de bucle.

  2. Guardando esa cadena en una variable curr_arg_label.

  3. Pasando ambas cadenas (!curr_arg_label!) y el nombre de una variable de retorno (curr_arg_value) a un subprograma primitivo get_value.

  4. En el subprograma (%1) el valor de su primer argumento se utiliza en el lado izquierdo de la asignación (set) y (%2) el valor de su segundo argumento a la derecha. Sin embargo, cuando se pasa el argumento del segundo subprograma, el intérprete de comandos lo resuelve en el valor del argumento de línea de comando del programa principal. Es decir, lo que se pasa no es, por ejemplo, "% 4", sino cualquier valor que tenga la cuarta variable de argumento de la línea de comando ("another_arg" en el uso de la muestra).

  5. Luego se prueba que la variable dada al subprograma como variable de retorno (curr_arg_value) no está definida, lo que sucedería si el argumento de línea de comando evaluado actualmente está ausente. Inicialmente, esta fue una comparación del valor de la variable de retorno entre corchetes vacíos (que es la única manera que conozco de probar el programa o los argumentos del subprograma que pueden contener comillas y fue un residuo pasado por alto de la fase de prueba y error) pero desde entonces se ha fijado en cómo está ahora.

+1

Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre cómo y/o por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta. – thewaywewere

+0

@thewaywe were thank you, sigo olvidando que para muchas personas (probablemente la mayoría) es mejor tener una descripción de texto en lugar de código "autoexplicativo". –

Cuestiones relacionadas