File batch: numero di argomenti della riga di comando


99

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.

per esempio. se hai:

myapp foo bar

Nel guscio:

  • $ # -> 2
  • $ * -> foo bar
  • $ 0 -> miaapp
  • $ 1 -> pippo
  • $ 2 -> bar

In batch

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

Quindi mi sono guardato intorno e o sto cercando nel punto sbagliato o sono cieco, ma non riesco a trovare un modo per ottenere il conteggio del numero di argomenti della riga di comando passati.

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

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


la tua stringa è 2 myapp foo bar?
PsychoData

2
consiglio: non convertire sh in BAT. invece, scarica cygwin e usalo invece. cioè i tuoi script sh funzioneranno su una macchina Windows. e non dovrai tradurre ogni sh in BAT!
Marty McGowan

Risposte:


104

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 tempi DOS :)


7
Nota che questa variante di forfunziona solo per argomenti che assomigliano a nomi di file, non stringhe di opzioni come -?. L'utilizzo di quotes ( for %%i in ("%*") ...) funziona per argomenti simili, -?ma fallisce ancora per gli argomenti tra virgolette a causa delle virgolette annidate. L'unico modo robusto sembra coinvolgere shift...
Ferdinand Beyer

1
MyBatchFile "*.*" "Abc"segnala che argC == 9. - Downvoted.
BrainSlugs83

L'ho testato su 2500 argomenti come funzione e l'ho usato per definire array della stessa dimensione. Non chiedermi perché esattamente. Principalmente sto solo imparando di cosa è capace il batch.
T3RR0R

44

Tendi 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

eccetera.

Se hai più di 9 argomenti, allora sei fottuto con questo approccio. Ci sono vari hack per la creazione di contatori che puoi trovare qui , ma tieni presente che non sono per i deboli di cuore.


6
Puoi ancora usare shiftper contare più di 9 ... e senza avere 10 righe di codice dall'aspetto uguale.
Joey il

19

La funzione di :getargcseguito potrebbe essere quello 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 sull'elenco (che è locale rispetto alla funzione in modo che i turni non influenzino l'elenco nel programma principale), contandoli fino a quando non si esaurisce.

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

Il programma principale illustra solo come chiamarlo e fa eco gli argomenti in seguito per assicurarsi che siano intatti:

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"

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

@ n611x007 dove echo Count is %argc%inseriresti il ​​tuo codice che potrebbe verificare se quel conteggio è corretto e poi andare avanti.
kenny

7

Prova questo:

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

6
questa risposta è in qualche modo diversa da quella di @nimrod ? ...
bluastro

1
controlla il commento di @FerdinandBeyer in nimrodm's. non downvote perché hai 21 rep 8)
n611x007

6

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

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 di utilizzare uno shifto un forciclo a scapito 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
)

Produzione:

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 implica:

  1. Costruzione di una stringa che rappresenta una variabile di argomento della riga di comando attualmente valutata (ad esempio "% 1", "% 2" ecc.) Utilizzando una stringa che contiene un carattere di percentuale ( %%) e una variabile contatore arg_idxsu ciascuna iterazione del ciclo.

  2. Memorizzare quella stringa in una variabile curr_arg_label.

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

  4. Nel sottoprogramma il valore del suo primo argomento ( %1) viene utilizzato a sinistra di assignment ( set) e il valore del secondo argomento ( %2) a destra. Tuttavia, quando l'argomento del secondo sottoprogramma viene passato, viene risolto nel valore dell'argomento della riga di comando del programma principale dall'interprete dei comandi. Cioè, ciò che viene passato non è, ad esempio, "% 4" ma qualunque valore contenga la quarta variabile dell'argomento della riga di comando ("another_arg" nell'utilizzo di esempio).

  5. Quindi la variabile data al sottoprogramma come variabile di ritorno ( curr_arg_value) viene testata per non essere definita, cosa che accadrebbe se l'argomento della riga di comando attualmente valutato è assente. Inizialmente questo era un confronto del valore della variabile di ritorno racchiuso tra parentesi quadre con parentesi quadre vuote (che è l'unico modo che conosco per testare argomenti di programmi o sottoprogrammi che possono contenere virgolette ed era un residuo trascurato dalla fase di tentativi ed errori) ma da allora è stato fissato a com'è ora.


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

@thewaywewere grazie, continuo a dimenticare che per molte persone (probabilmente la maggioranza) è meglio avere una descrizione testuale invece di un codice "autoesplicativo".
fen-fire

@ fen-fire tranne che il codice non è autoesplicativo.
Loduwijk

1

L'ultima risposta risale a due anni fa, ma avevo bisogno di una versione per più di nove argomenti della riga di comando. Può essere anche un altro ...

@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 soluzione sono le prime 19 righe e converte tutti gli argomenti in variabili in uno stile simile a C. Tutte le altre cose si limitano a esaminare il risultato e mostrano la conversione in argomenti locali. Puoi fare riferimento agli argomenti in base all'indice in qualsiasi funzione.


0

Una soluzione robusta è delegare il conteggio a una subroutine invocata con call; la subroutine utilizza le gotoistruzioni per emulare un ciclo in cui shiftviene utilizzato per consumare gli argomenti (solo subroutine) in modo iterativo:

@echo off
setlocal

:: Call the argument-counting subroutine with all arguments received,
:: without interfering with the ability to reference the arguments
:: with %1, ... later.
call :count_args %*

:: Print the result.
echo %ReturnValue% argument(s) received.

:: Exit the batch file.
exit /b

:: Subroutine that counts the arguments given.
:: Returns the count in %ReturnValue%
:count_args
  set /a ReturnValue = 0
  :count_args_for

    if %1.==. goto :eof

    set /a ReturnValue += 1

    shift
  goto count_args_for
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.