2009-08-18 5 views
77

Basta convertire alcuni script di shell in file batch e c'è una cosa che non riesco a trovare ... e questo è un semplice conteggio del numero di argomenti della riga di comando.File batch: numero di argomenti della riga di comando

es. se si dispone di:

myapp foo bar 

In Shell:

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

Nel lotto

  • ?? -> 2 < ---- quale comando ?!
  • % * -> foo bar
  • % 0 -> myapp
  • % 1 -> foo
  • % 2 -> bar

Così ho guardato in giro, e mi sia sto cercando nel posto sbagliato o sono cieco, ma non riesco a trovare un modo per ottenere un conteggio del numero di argomenti della linea di comando passati.

Esiste un comando simile a quello della shell "$ # "per i file batch?

ps. il più vicino che ho trovato è quello di scorrere il% 1s e usare 'shift', ma ho bisogno di refernece% 1,% 2 ecc più avanti nello script, quindi non va bene.

+0

la stringa è '2 myapp foo bar'? – PsychoData

+2

consiglio: non convertire sh in BAT. invece, scarica cygwin e usalo al suo posto. I tuoi script sh funzioneranno su una macchina Windows. e non dovrai tradurre ogni sh in BAT! –

risposta

81

Googling un po 'ti dà il seguente risultato da wikibooks:

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

echo %argC% 

Sembra che cmd.exe si sia evoluto un po 'dai vecchi giorni DOS :)

+7

Si noti che questa variante di 'for' funziona solo per argomenti che assomigliano a nomi di file, non a stringhe di opzioni come' -? '. Usare le virgolette ('per %% i in ("% * ") ...') funziona per argomenti come '-?' Ma fallisce ancora per gli argomenti citati a causa di virgolette nidificate. L'unico modo efficace sembra implicare 'shift' ... –

+1

scusa, downvoted a causa di ciò che @FerdinandBeyer dice – n611x007

33

si tende a gestire il numero di argomenti con questo tipo di logica:

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

ecc

Se si dispone di più di 9 argomenti allora si sono avvitati con questo approccio però. Esistono vari hack per la creazione di contatori che puoi trovare here, ma tieni presente che questi non sono per i deboli di cuore.

+3

Puoi ancora usare 'shift' per contare più di 9 ...e senza avere 10 linee di codice uguali. – Joey

18

La funzione :getargc qui sotto può essere ciò che stai cercando.

@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 

'fondamentalmente itera una volta oltre la lista (che è locale alla funzione in modo che i cambiamenti non influenzeranno la lista nel programma principale), contando loro fino a quando non si esaurisce.

Utilizza anche un trucco elegante, passando il nome della variabile di ritorno che deve essere impostata dalla funzione.

Il programma principale illustra solo come chiamare e echos gli argomenti in seguito al fine di garantire che siano intatte:

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

come puoi modificare il flusso in base a questo? (potrebbe essere una domanda diversa, ma penso che un breve esempio sarebbe anche molto conveniente qui!) – n611x007

+0

@ n611x007 dove il 'eco count è% argc%' inseriresti il ​​tuo codice che potrebbe controllare se quel conteggio è corretto e poi Vai avanti. – kenny

6

Prova questo:

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

è questa risposta in qualche modo diversa da [@nimrod one] (http://stackoverflow.com/a/1292094/505893) ? ... – bluish

+0

controlla il commento di @FerdinandBeyer in nimrodm. non andrà giù perché hai 21 rep 8) – n611x007

5

Se il numero di argomenti dovrebbe essere un numero esatto (minore o uguale a 9), allora questo è un modo semplice per controllare:

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 utilizzando shift o un ciclo for a il costo delle dimensioni e della leggibilità.

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

uscita:

count_cmdline_args.bat testing more_testing arg3 another_arg 

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

EDIT: Il "trucco" usato qui comporta:

  1. Costruire una stringa che rappresenta una variabile argomento della riga di comando attualmente valutato (cioè "% 1 ","% 2 "ecc.) Utilizzando una stringa che contiene un carattere percentuale (%%) e una variabile contatore arg_idx su ogni ciclo iterativo.

  2. Memorizzazione di tale stringa in una variabile curr_arg_label.

  3. Passando sia quella stringa (!curr_arg_label!) sia il nome di una variabile di ritorno (curr_arg_value) in un sottoprogramma primitivo get_value.

  4. Nel sottoprogramma (%1) valore suo primo argomento viene utilizzato sul lato sinistro di assegnazione (set) e (%2) valore sua seconda dell'argomento a destra. Tuttavia, quando viene passato l'argomento del secondo sottoprogramma, viene risolto in valore dall'argomento della riga di comando del programma principale da parte dell'interprete dei comandi. Cioè, ciò che viene passato non è, ad esempio, "% 4", ma qualunque valore valga la quarta variabile argomento della riga di comando ("another_arg" nell'uso di esempio).

  5. Quindi la variabile assegnata al sottoprogramma come variabile di ritorno (curr_arg_value) viene verificata per essere indefinita, cosa che succederebbe se l'argomento della riga di comando attualmente valutato fosse assente. Inizialmente si trattava di un confronto del valore della variabile di ritorno racchiuso tra parentesi quadre per svuotare le parentesi quadre (che è l'unico modo che conosco degli argomenti del programma di test o di sottoprogramma che possono contenere virgolette ed era un residuo trascurato dalla fase di prova ed errore) ma è stato fissato su come è ora.

+1

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo riguardo a come e/o perché risolve il problema migliorerebbe il valore a lungo termine della risposta. – thewaywewere

+0

@thewaywewere, grazie, continuo a dimenticare che per molte persone (probabilmente la maggior parte) è meglio avere una descrizione di testo anziché un codice "auto-esplicativo". –