2009-08-18 1 views
77

Nur einige Shell-Skripte in Batch-Dateien konvertieren und es gibt eine Sache, die ich nicht finden kann ... und das ist eine einfache Anzahl der Anzahl der Befehlszeilenargumente.Batch-Dateien - Anzahl der Befehlszeilenargumente

z. wenn Sie:

myapp foo bar 

In Shell:

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

Im Stapel

  • ?? -> 2 < ---- welcher Befehl ?!
  • % * -> foo bar
  • % 0 -> myapp
  • % 1 -> foo
  • % 2 -> bar

Also habe ich mich umsah, und entweder I bin an der falschen Stelle oder ich bin blind, aber ich kann nicht scheinen, einen Weg zu finden, um die Anzahl der übergebenen Kommandozeilenargumente zu erhalten.

Gibt es einen Befehl ähnlich wie Shell "$ # "für Batch-Dateien?

ps. Das nächste, was ich gefunden habe, ist die% 1s zu durchlaufen und 'shift' zu verwenden, aber ich muss später% 1,% 2 usw. im Skript referenzieren, das ist nicht gut.

+0

Ihre Saite ist '2 myapp foo bar'? – PsychoData

+2

Hinweis: Sh nicht in BAT konvertieren. stattdessen, laden Sie Cygwin herunter und verwenden Sie es stattdessen. Das heißt, Ihre SH-Skripte funktionieren auf einem Windows-Rechner. und du musst nicht jedes sh zu BAT übersetzen! –

Antwort

81

googeln ein bisschen Sie das folgende Ergebnis aus wikibooks gibt:

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

echo %argC% 

Scheint wie cmd.exe hat sich ein wenig von den alten DOS-Tagen entwickelt :)

+7

Beachten Sie, dass diese Variante von 'for' nur für Argumente funktioniert, die wie Dateinamen aussehen, nicht für Optionszeichenfolgen wie' -? '. Die Verwendung von Anführungszeichen ('für %% i in ("% * ") ...') funktioniert für Argumente wie '-?', Scheitert aber wiederum an in Anführungszeichen gesetzten Argumenten aufgrund verschachtelter Anführungszeichen. Der einzige stabile Weg scheint 'shift' zu sein ... –

+1

Entschuldigung, downvoted wegen dem was @FerdinandBeyer sagt – n611x007

33

Sie neigen dazu, mit dieser Art von Logik Anzahl von Argumenten zu handhaben:

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

usw.

Wenn Sie mehr als 9 Argumente haben dann Sie aber mit diesem Ansatz eingeschraubt werden. Es gibt verschiedene Hacks zum Erstellen von Zählern, die Sie finden können here, aber seien Sie gewarnt, diese sind nicht für schwache Nerven.

+3

Sie können 'shift' verwenden, um mehr als 9 zu zählen ...und ohne 10 Zeilen von gleich aussehendem Code zu haben. – Joey

18

Die Funktion :getargc unten kann sein, was Sie suchen.

@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 

Es besteht im Wesentlichen Iterierten einmal über die Liste (die die Funktion lokal ist, so dass die Verschiebungen werden die Liste nicht zurück in dem Hauptprogramm beeinflussen), sie zu zählen, bis es abläuft.

Es verwendet auch einen raffinierten Trick, den Namen der Rückgabevariablen übergeben, die von der Funktion festgelegt werden.

Das Hauptprogramm zeigt, wie es nennen und Echos, die Argumente danach, um sicherzustellen, dass sie unberührt sind:

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

Wie können Sie den Durchfluss auf dieser Basis ändern? (kann eine andere Frage sein, aber ich denke, ein kurzes Beispiel wäre auch hier sehr praktisch!) – n611x007

+0

@ n611x007 wo die Echo-Zählung% argc% ist, würden Sie Ihren eigenen Code einfügen, der prüfen könnte, ob diese Zählung korrekt ist und dann mach weiter. – kenny

6

Versuchen Sie dies:

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

ist diese Antwort irgendwie anders als [@nimrod one] (http://Stackoverflow.com/a/1292094/505893) ? ... – bluish

+0

Kommentar von @FerdinandBeyer in Nimrodm überprüfen. nicht downvote, weil Sie 21 rep haben 8) – n611x007

5

Wenn die Anzahl der Argumente sollte eine genaue Zahl (weniger oder gleich 9), dann ist dies ein einfacher Weg, um es zu überprüfen:

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

Vermeidet entweder shift oder einen for Zyklus bei die Kosten für Größe und Lesbarkeit.

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

Ausgang:

count_cmdline_args.bat testing more_testing arg3 another_arg 

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

EDIT: Der "Trick" verwendet hier beinhaltet:

  1. eine Zeichenfolge erstellt, die eine zur Zeit ausgewertet Befehlszeilenargument Variablen (dh „für% 1 ","% 2 "usw.) mit einer Zeichenfolge, die ein Prozentzeichen (%%) und eine Zählervariable arg_idx für jede Schleifeniteration enthält.

  2. Speichern dieser Zeichenfolge in einer Variablen curr_arg_label.

  3. Übergabe dieser Zeichenfolge (!curr_arg_label!) und des Namens einer Rückgabevariablen (curr_arg_value) an ein primitives Unterprogramm get_value.

  4. In dem Unterprogramm seine erste Argument der (%1) Wert wird auf der linken Seite der Zuweisung verwendet (set) und dessen zweites Argument (%2) Wert auf der rechten Seite. Wenn das Argument des zweiten Unterprogramms jedoch übergeben wird, wird es durch den Befehlsinterpreter in den Wert des Befehlszeilenarguments des Hauptprogramms aufgelöst. Das heißt, nicht "% 4" wird übergeben, sondern jeder Wert, den die vierte Befehlszeilenargumentvariable enthält ("another_arg" in der Beispielverwendung).

  5. Dann wird die Variable auf das Unterprogramm als Rückgabevariable gegeben (curr_arg_value) wird für undefiniert getestet, was fehlt, wenn zur Zeit ausgewertet Befehlszeilenargument passieren würde, ist. Anfangs war dies ein Vergleich des Wertes der Rückgabevariable in eckigen Klammern mit leeren eckigen Klammern (das ist die einzige Art, wie ich Programm- oder Unterprogrammargumente kenne, die Anführungszeichen enthalten können und ein übersehener Überrest der Trial-and-Error-Phase waren) war seitdem fest, wie es jetzt ist.

+1

Während dieser Code die Frage beantworten kann, die Bereitstellung von zusätzlichen Kontext in Bezug darauf, wie und/oder warum es das Problem löst würde den langfristigen Wert der Antwort verbessern. – thewaywewere

+0

@thewaywewere danke, ich vergesse immer wieder, dass es für viele Leute (wahrscheinlich die Mehrheit) besser ist, eine Textbeschreibung anstelle von "selbsterklärendem" Code zu haben. –