2009-08-18 14 views
77

Przekształcanie niektórych skryptów powłoki w pliki wsadowe i jest jedna rzecz, której nie mogę znaleźć ... i to jest prosta liczba argumentów wiersza poleceń.Pliki wsadowe - liczba argumentów wiersza poleceń

np. jeśli masz:

myapp foo bar 

skorupek:

  • $ # -> 2
  • $ * -> foo bar
  • $ 0 -> MojaApl
  • $ 1 -> foo
  • $ 2 -> pasek

W partii

  • ?? -> 2 < ---- jakie polecenie ?!
  • % * -> foo bar
  • % 0 -> MojaApl
  • % 1 -> foo
  • % 2 -> bar

Więc szukałem wokół, i albo ja patrzę w niewłaściwym miejscu lub jestem ślepy, ale nie potrafię znaleźć sposobu na zliczenie liczby argumentów z linii poleceń.

Czy istnieje polecenie podobne do powłoki "$ # "w przypadku plików wsadowych?

ps. najbliższym znalezieniem jest iteracja przez% 1 i użycie 'shift', ale muszę ponownie zapisać% 1,% 2 itd. w skrypcie, więc to nie jest dobre.

+0

Twój ciąg to '2 myapp foo bar'? Porada – PsychoData

+2

: nie konwertuj sh na BAT. zamiast tego pobierz cygwin i użyj go zamiast tego. np. twoje skrypty sh będą działać na maszynie Windows. i nie będziesz musiał tłumaczyć każdego sh na BAT! –

Odpowiedz

81

Googling trochę daje następujący wynik z wikibooks:

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

echo %argC% 

Wygląda na to, że cmd.exe ewoluował nieco ze starych dni DOS :)

+7

Zauważ, że ten wariant 'for' działa tylko dla argumentów, które wyglądają jak nazwy plików, a nie z łańcuchów opcji, takich jak' -? '. Używanie cudzysłowów ('dla %% i in ("% * ") ...') działa dla argumentu takiego jak '-?', Ale znowu nie ma argumentów cytowanych z powodu zagnieżdżonych cudzysłowów. Jedyny solidny sposób wydaje się obejmować "przesunięcie" ... –

+1

przepraszam, odrzucono z powodu tego, co @FerdinandBeyer mówi – n611x007

33

Masz tendencję do obsługi liczbę argumentów z tego rodzaju logiką:

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

itp

Jeśli masz więcej niż 9 argumentów następnie przykręca się z tym podejściem chociaż. Istnieją różne hacki do tworzenia liczników, które można znaleźć here, ale należy pamiętać, że nie są one dla osób o słabym sercu.

+3

Możesz nadal używać 'shift', aby policzyć więcej niż 9 ...i bez posiadania 10 linii równie wyglądającego kodu. – Joey

18

Poniżej znajduje się funkcja :getargc, której szukasz.

@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 

Zasadniczo iteracje raz na listę (który jest lokalny do funkcji przesunięcia tak nie będzie miało wpływu na listy z powrotem w programie głównym), licząc je, aż się skończy.

Używa również sprytnej sztuczki, przekazując nazwę zmiennej powrotnej, która ma być ustawiona przez funkcję.

Główny program tylko pokazuje, jak to nazwać i Echos argumenty potem, aby zapewnić, że są nietknięte:

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

jak można zmienić przepływ w oparciu o to? (może być inne pytanie, ale myślę, że krótki przykład byłby również bardzo wygodny tutaj!) – n611x007

+0

@ n611x007 gdzie 'liczba echa to% argc%' wstawiałbyś swój własny kod, który mógłby sprawdzić, czy ta liczba jest poprawna, a następnie pójść dalej. – kenny

6

Spróbuj tego:

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

jest to odpowiedź w pewien sposób różna od [@nimrod jeden] (http://stackoverflow.com/a/1292094/505893) ? ... – bluish

+0

sprawdź komentarz przez @FerdinandBeyer w nimrodmie. nie stracisz, ponieważ masz 21 rep 8) – n611x007

5

Jeśli liczba argumentów powinien być dokładną liczbę (mniejszą lub równą 9), to jest to prosty sposób, aby to sprawdzić:

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

Unika stosując albo shift lub cykl przy for koszt rozmiaru i czytelności.

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

wyjściowa:

count_cmdline_args.bat testing more_testing arg3 another_arg 

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

EDIT: "trick" stosowany tu dotyczy:

  1. Konstruowanie ciąg, który reprezentuje zmienną obecnie badane argument wiersza poleceń (czyli „% 1 ","% 2 "itp.) Za pomocą ciągu znaków zawierającego znak procentowy (%%) i zmienną licznika arg_idx dla każdej iteracji pętli.

  2. Przechowywanie tego ciągu w zmiennej curr_arg_label.

  3. Przekazanie obu znaków (!curr_arg_label!) i nazwy zmiennej zwrotnej (curr_arg_value) do prymitywnego podprogramu get_value.

  4. W podprogramie (%1) Wartość pierwszy argument jest stosowany po lewej stronie przypisania (set) i (%2) wartości drugi argument jest na prawo. Jednakże, gdy argument drugiego podprogramu zostanie przekazany, zostaje on przetłumaczony na wartość argumentu wiersza poleceń programu głównego przez interpreter poleceń. Oznacza to, że nie jest, na przykład, "% 4", ale niezależnie od wartości, która zawiera czwarta zmienna argumentowa wiersza poleceń ("inny_arg" w użyciu próbki).

  5. Następnie zmienna podana do podprogramu jako zmienna zwrotna (curr_arg_value) jest testowana pod kątem niezdefiniowania, co nastąpiłoby, gdyby aktualnie nie sprawdzono argumentu linii poleceń. Początkowo było to porównanie wartości zmiennej zwracanej zawiniętej w nawiasy kwadratowe z pustymi nawiasami kwadratowymi (co jest jedynym sposobem, w jaki znam program testowy lub argumenty podprogramu, które mogą zawierać cytaty i były przeoczone z fazy prób i błędów), ale od tego czasu został naprawiony.

+1

Podczas gdy ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i/lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi. – thewaywewere

+0

@thewaywewere dziękuję, ciągle zapominam, że dla wielu osób (prawdopodobnie większość) lepiej jest mieć opis tekstowy zamiast "objaśniającego się" kodu. –

Powiązane problemy