Toplu iş dosyaları - komut satırı bağımsız değişkenlerinin sayısı


100

Sadece bazı kabuk komut dosyalarını toplu iş dosyalarına dönüştürmek ve bulamadığım bir şey var ... ve bu komut satırı argümanlarının sayısının basit bir sayısı.

Örneğin. eğer varsa:

myapp foo bar

Kabukta:

  • $ # -> 2
  • $ * -> foo çubuğu
  • $ 0 -> uygulamam
  • $ 1 -> foo
  • $ 2 -> çubuk

Parti halinde

  • ?? -> 2 <---- hangi komut ?!
  • % * -> foo çubuğu
  • % 0 -> uygulamam
  • % 1 -> foo
  • % 2 -> çubuk

Bu yüzden etrafıma baktım ve ya yanlış noktaya bakıyorum ya da kör oluyorum, ancak aktarılan komut satırı argümanlarının sayısını elde etmenin bir yolunu bulamıyorum.

Toplu dosyalar için kabuğun "$ #" komutuna benzer bir komut var mı?

ps. Bulduğum en yakın şey% 1'ler boyunca yinelemek ve 'shift' kullanmak, ancak komut dosyasında daha sonra% 1,% 2 vb. başvurmam gerekiyor, bu yüzden bu iyi değil.


sizin dizedir 2 myapp foo bar?
PsychoData

2
tavsiye: sh'yi BAT'a dönüştürmeyin. bunun yerine cygwin'i indirin ve kullanın. yani, sh betikleriniz bir Windows makinesinde çalışacaktır. ve her şeyi BAT'a çevirmek zorunda kalmayacaksınız!
Marty McGowan

Yanıtlar:


107

Biraz Google'da arama yapmak, wikibook'lardan aşağıdaki sonucu verir :

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

echo %argC%

Görünüşe göre cmd.exe eski DOS günlerinden beri biraz gelişti :)


7
Bu varyantın foryalnızca dosya adlarına benzeyen argümanlar için çalıştığını -?,. Quotes ( for %%i in ("%*") ...) kullanmak argüman gibi çalışır -?ancak iç içe geçmiş tırnaklar nedeniyle alıntılanan argümanlar için yine başarısız olur. Tek sağlam yol şunları içeriyor gibi görünüyor shift...
Ferdinand Beyer

1
MyBatchFile "*.*" "Abc"argC == 9. - Olumsuz oy verildiğini bildirir.
BrainSlugs83

Bunu bir işlev olarak 2500 argümana kadar test ettiniz ve aynı boyuttaki dizileri tanımlamak için kullandınız. Bana tam olarak neden diye sorma. Çoğunlukla sadece partinin neler yapabileceğini öğrenmek.
T3RR0R

45

Bu tür bir mantıkla birçok argümanı ele alma eğilimindesiniz:

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

vb.

9'dan fazla argümanınız varsa, o zaman bu yaklaşımla mahvolursunuz. Orada bulabilirsiniz sayaçları oluşturmak için çeşitli kesmek vardır burada , ancak bu yürekli zayıf olanlara değil uyarılmalıdır.


6
Yine de shift9'dan fazla saymak için kullanabilirsiniz ... ve eşit görünen 10 satır kod olmadan.
Joey

19

Aşağıdaki işlev :getargc, aradığınız şey olabilir.

@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

Temelde liste üzerinde bir kez yineler (bu işlev için yereldir, böylece vardiyalar listeyi ana programda etkilemez), bitene kadar onları sayar.

Ayrıca, işlev tarafından ayarlanacak dönüş değişkeninin adını ileten şık bir numara kullanır.

Ana program sadece onu nasıl çağıracağını gösterir ve daha sonra dokunulmadıklarından emin olmak için argümanları yansıtır:

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"

buna göre akışı nasıl değiştirebilirsin? (farklı bir soru olabilir, ancak burada kısa bir örnek de çok uygun olur!)
n611x007

@ n611x007 burada, sayının echo Count is %argc%uygun olup olmadığını kontrol edebilecek kendi kodunuzu ekleyip sonra devam edersiniz.
kenny

7

Bunu dene:

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

6
bu cevap @ nimrod one'dan biraz farklı mı? ...
mavimsi

1
nimrodm'da @ FerdinandBeyer tarafından yapılan yorumu kontrol edin. olumsuz oy vermeyeceksin çünkü 21 tekrarın var 8)
n611x007

6

Bağımsız değişkenlerin sayısı tam bir sayı olmalıdır (9'a eşit veya küçükse), bu, onu kontrol etmenin basit bir yoludur:

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

Boyut ve okunabilirlik pahasına shiftbir fordöngü kullanmaktan kaçınır .

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

Çıktı:

count_cmdline_args.bat testing more_testing arg3 another_arg

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

DÜZENLEME: Burada kullanılan "numara" şunları içerir:

  1. Yüzde karakteri ( %%) içeren bir dize ve arg_idxher döngü yinelemesinde bir sayaç değişkeni kullanarak şu anda değerlendirilmiş bir komut satırı bağımsız değişkenini (yani "% 1", "% 2" vb.) Temsil eden bir dize oluşturmak .

  2. Bu dizeyi bir değişkene depolamak curr_arg_label.

  3. Hem bu dizeyi ( !curr_arg_label!) hem de bir dönüş değişkeninin adını ( curr_arg_value) ilkel bir alt programa geçirmek get_value.

  4. Alt programda, birinci bağımsız değişkeninin ( %1) değeri atamanın ( set) sol tarafında ve ikinci bağımsız değişkeninin ( %2) değeri sağda kullanılır. Bununla birlikte, ikinci alt programın argümanı iletildiğinde, komut yorumlayıcısı tarafından ana programın komut satırı argümanının değerine çözümlenir. Yani iletilen, örneğin "% 4" değil, dördüncü komut satırı bağımsız değişkeninin tuttuğu değerdir (örnek kullanımda "another_arg").

  5. Daha sonra, alt programa dönüş değişkeni ( curr_arg_value) olarak verilen değişkenin tanımsız olup olmadığı test edilir ve bu, halihazırda değerlendirilen komut satırı argümanı yoksa olur. Başlangıçta bu, dönüş değişkeninin değerinin köşeli parantez içine alınmış boş köşeli parantezlerle karşılaştırılmasıydı (bu, tırnak işaretleri içerebilen ve deneme yanılma aşamasından gözden kaçan bir kalıntı olan program veya alt program argümanlarını test etmeyi bildiğim tek yoldur) ancak o zamandan beri şimdi nasıl olduğuna sabitlendi.


1
Bu kod soruyu yanıtlayabilirken, sorunun nasıl ve / veya neden çözüldüğüne ilişkin ek bağlam sağlamak, yanıtlayanın uzun vadeli değerini artıracaktır.
thewaywewere

@thewaywere teşekkür ederim, birçok insan için (muhtemelen çoğunluk) "kendi kendini açıklayan" kod yerine bir metin açıklamasına sahip olmanın daha iyi olduğunu unutuyorum.
fen-fire

@ fen-fire, ancak kodun kendi kendini açıklayıcı olmaması.
Loduwijk

1

Son cevap iki yıl önceydi, ancak dokuzdan fazla komut satırı argümanı için bir sürüme ihtiyacım vardı. Belki başka biri de yapar ...

@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

Çözüm ilk 19 satırdır ve tüm argümanları c benzeri bir tarzda değişkenlere dönüştürür. Diğer tüm şeyler sonucu araştırır ve yerel bağımsız değişkenlere dönüşümü gösterir. Herhangi bir işlevde dizine göre bağımsız değişkenlere başvurabilirsiniz.


0

Sağlam bir çözüm, sayımı ile çağrılan bir alt rutine delege etmektir call; alt rutin , (yalnızca alt rutin) bağımsız değişkenleri yinelemeli olarak tüketmek için kullanılan gotobir döngüyü taklit etmek için ifadeler kullanır shift:

@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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.