File batch - jumlah argumen baris perintah


99

Hanya mengubah beberapa skrip shell menjadi file batch dan ada satu hal yang sepertinya tidak dapat saya temukan ... dan itu adalah hitungan sederhana dari jumlah argumen baris perintah.

misalnya. jika Anda memiliki:

myapp foo bar

Di Shell:

  • $ # -> 2
  • $ * -> bilah foo
  • $ 0 -> aplikasi saya
  • $ 1 -> foo
  • $ 2 -> bar

Dalam batch

  • ?? -> 2 <---- perintah apa ?!
  • % * -> bilah foo
  • % 0 -> aplikasi saya
  • % 1 -> foo
  • % 2 -> bar

Jadi saya telah melihat sekeliling, dan entah saya mencari di tempat yang salah atau saya buta, tetapi sepertinya saya tidak dapat menemukan cara untuk menghitung jumlah argumen baris perintah yang diteruskan.

Apakah ada perintah yang mirip dengan shell "$ #" untuk file batch?

ps. yang paling dekat yang saya temukan adalah mengulang melalui% 1s dan menggunakan 'shift', tetapi saya perlu merujuk% 1,% 2 dll nanti di skrip jadi itu tidak bagus.


string Anda 2 myapp foo bar?
PsychoData

2
saran: jangan ubah sh menjadi BAT. sebagai gantinya, unduh cygwin dan gunakan sebagai gantinya. yaitu skrip sh Anda akan bekerja pada mesin windows. dan Anda tidak perlu menerjemahkan setiap sh ke BAT!
Marty McGowan

Jawaban:


104

Sedikit googling memberi Anda hasil berikut dari wikibook :

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

echo %argC%

Sepertinya cmd.exe telah berevolusi sedikit dari masa DOS sebelumnya :)


7
Perhatikan bahwa varian ini forhanya berfungsi untuk argumen yang terlihat seperti nama file, bukan string opsi seperti -?. Menggunakan tanda kutip ( for %%i in ("%*") ...) berfungsi untuk argumen seperti -?tetapi sekali lagi gagal untuk argumen yang dikutip karena kutipan bertingkat. Satu-satunya cara yang kuat tampaknya melibatkan shift...
Ferdinand Beyer

1
MyBatchFile "*.*" "Abc"melaporkan bahwa argC == 9. - Suara negatif.
BrainSlugs83

Telah mengujinya pada 2500 argumen sebagai fungsi dan menggunakannya untuk mendefinisikan array dengan ukuran yang sama. Jangan tanya saya kenapa tepatnya. Sebagian besar hanya mempelajari kemampuan batch.
T3RR0R

44

Anda cenderung menangani sejumlah argumen dengan logika semacam ini:

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

dll.

Jika Anda memiliki lebih dari 9 argumen maka Anda kacau dengan pendekatan ini. Ada berbagai peretasan untuk membuat penghitung yang dapat Anda temukan di sini , tetapi berhati-hatilah karena ini bukan untuk yang lemah hati.


6
Anda masih dapat menggunakan shiftuntuk menghitung lebih dari 9 ... dan tanpa 10 baris kode yang tampak sama.
Joey

19

Fungsi di :getargcbawah ini mungkin yang Anda cari.

@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

Ini pada dasarnya mengulang sekali daftar (yang merupakan fungsi lokal sehingga pergeseran tidak akan mempengaruhi daftar kembali di program utama), menghitungnya sampai habis.

Ini juga menggunakan trik bagus, meneruskan nama variabel return yang akan disetel oleh fungsi.

Program utama hanya mengilustrasikan bagaimana memanggilnya dan menggemakan argumen setelahnya untuk memastikan bahwa mereka tidak tersentuh:

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"

bagaimana Anda bisa mengubah aliran berdasarkan ini? (mungkin pertanyaan yang berbeda, tapi saya pikir contoh singkat juga akan sangat nyaman di sini!)
n611x007

@ n611x007 di mana echo Count is %argc%Anda akan memasukkan kode Anda sendiri yang dapat memeriksa apakah hitungan itu tepat dan kemudian melanjutkan.
kenny

7

Coba ini:

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

6
apakah jawaban ini berbeda dari @nimrod one ? ...
kebiru

1
periksa komentar oleh @FerdinandBeyer di nimrodm. tidak akan downvote karena Anda memiliki 21 rep 8)
n611x007

6

Jika jumlah argumen harus berupa angka eksak (kurang atau sama dengan 9), maka ini adalah cara sederhana untuk memeriksanya:

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

Hindari penggunaan salah satu shiftatau forsiklus dengan mengorbankan ukuran dan keterbacaan.

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

Keluaran:

count_cmdline_args.bat testing more_testing arg3 another_arg

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

EDIT: "Trik" yang digunakan di sini melibatkan:

  1. Membangun string yang mewakili variabel argumen baris perintah yang sedang dievaluasi (yaitu "% 1", "% 2" dll.) Menggunakan string yang berisi karakter persen ( %%) dan variabel penghitung arg_idxpada setiap pengulangan perulangan.

  2. Menyimpan string itu ke dalam variabel curr_arg_label.

  3. Meneruskan string ( !curr_arg_label!) dan nama variabel kembalian ( curr_arg_value) ke subprogram primitif get_value.

  4. Dalam subprogram, nilai argumen pertama ( %1) digunakan di sisi kiri assignment ( set) dan nilai argumen kedua ( %2) di sisi kanan. Namun, ketika argumen subprogram kedua dilewatkan, argumen tersebut diselesaikan menjadi nilai argumen baris perintah program utama oleh penerjemah perintah. Artinya, apa yang diteruskan bukanlah, misalnya, "% 4" tetapi berapa pun nilai yang dimiliki variabel argumen baris perintah keempat ("another_arg" dalam penggunaan sampel).

  5. Kemudian variabel yang diberikan ke subprogram sebagai variabel kembalian ( curr_arg_value) diuji karena tidak ditentukan, yang akan terjadi jika argumen baris perintah yang saat ini dievaluasi tidak ada. Awalnya ini adalah perbandingan nilai variabel kembalian yang dibungkus dalam tanda kurung siku dengan tanda kurung siku kosong (yang merupakan satu-satunya cara saya mengetahui program pengujian atau argumen subprogram yang mungkin berisi tanda kutip dan merupakan sisa yang diabaikan dari fase trial-and-error) tetapi sejak ditetapkan ke bagaimana sekarang.


1
Meskipun kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang bagaimana dan / atau mengapa kode ini memecahkan masalah akan meningkatkan nilai jawaban jangka panjang.
thewaywewere

@thewaywewere terima kasih, saya terus lupa bahwa bagi banyak orang (kemungkinan besar mayoritas) lebih baik memiliki deskripsi teks daripada kode "penjelasan sendiri".
fen-fire

@ fen-fire kecuali kodenya tidak cukup jelas.
Loduwijk

1

Jawaban terakhir sekarang adalah dua tahun lalu, tetapi saya membutuhkan versi untuk lebih dari sembilan argumen baris perintah. Mungkin yang lain juga ...

@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

Solusinya adalah 19 baris pertama dan mengubah semua argumen menjadi variabel dalam gaya c-like. Semua hal lain hanya menyelidiki hasilnya dan menunjukkan konversi ke argumen lokal. Anda dapat mereferensikan argumen dengan indeks dalam fungsi apa pun.


0

Solusi yang tepat adalah dengan mendelegasikan penghitungan ke subrutin yang dipanggil dengan call; subrutin menggunakan gotopernyataan untuk meniru perulangan yang shiftdigunakan untuk menggunakan argumen (hanya subrutin) secara berulang:

@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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.