बैच फ़ाइलें - कमांड लाइन तर्कों की संख्या


99

बस कुछ शेल स्क्रिप्ट को बैच फ़ाइलों में परिवर्तित करना और एक चीज है जो मुझे नहीं मिल सकती है ... और यह कमांड लाइन के तर्कों की संख्या की एक सरल गणना है।

जैसे। यदि आपके पास है:

myapp foo bar

खोल में:

  • $ # -> 2
  • $ * -> फू बार
  • $ 0 -> myapp
  • $ 1 -> फू
  • $ 2 -> बार

बैच में

  • ?? -> 2 <---- क्या आज्ञा है ?!
  • % * -> फू बार
  • % 0 -> myapp
  • % 1 -> फू
  • % 2 -> बार

इसलिए मैंने चारों ओर देखा है, और या तो मैं गलत जगह देख रहा हूं या मैं अंधा हूं, लेकिन मैं कमांड लाइन के तर्कों की संख्या की एक संख्या प्राप्त करने का एक तरीका नहीं ढूंढ सकता हूं।

क्या बैच फ़ाइलों के लिए शेल के "$ #" के समान कमांड है?

ps। निकटतम आई ने पाया है कि% 1s के माध्यम से पुनरावृति करना और 'शिफ्ट' का उपयोग करना है, लेकिन मुझे स्क्रिप्ट में बाद में% 1,% 2 आदि को संदर्भित करने की आवश्यकता है ताकि कोई अच्छा न हो।


अपने स्ट्रिंग है 2 myapp foo bar?
साइकोडाटा

2
सलाह: श को बीएटी में न बदलें। इसके बजाय, cygwin डाउनलोड करें और इसके बजाय इसका उपयोग करें। यानी आपकी sh स्क्रिप्ट विंडोज़ मशीन पर काम करेगी। और आपको BAT में हर श का अनुवाद नहीं करना पड़ेगा!
मार्टी मैकगोवन

जवाबों:


104

थोड़ा सा गुगुल करने से आपको विकबूक से निम्न परिणाम प्राप्त होते हैं :

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

echo %argC%

Cmd.exe जैसा लगता है पुराने DOS दिनों से थोड़ा सा विकसित हुआ है :)


7
ध्यान दें कि यह संस्करण forकेवल तर्कों के लिए काम करता है जो फ़ाइल नामों की तरह दिखते हैं, जैसे विकल्प तार नहीं -?। उद्धरण ( for %%i in ("%*") ...) का उपयोग तर्क के लिए काम करता है, -?लेकिन फिर से उद्धृत उद्धरणों के कारण उद्धृत तर्क के लिए विफल रहता है। शामिल करने के लिए एकमात्र मजबूत तरीका लगता है shift...
फर्डिनेंड बेयर

1
MyBatchFile "*.*" "Abc"ऐसी रिपोर्टें जो argC == 9. - डाउनवोट की गईं।
BrainSlugs83

इसे 2500 तर्कों के लिए एक फ़ंक्शन के रूप में परीक्षण किया है और इसका उपयोग उसी आकार के सरणियों को परिभाषित करने के लिए किया है। न मुझसे पूछें कि वास्तव में क्यों। ज्यादातर सिर्फ यह सीखते हैं कि कौन सा बैच सक्षम है।
T3RR0R

44

आप इस तरह के तर्क के साथ तर्कों की संख्या को संभालते हैं:

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

आदि।

यदि आपके पास 9 से अधिक तर्क हैं तो आप इस दृष्टिकोण के साथ खराब हैं। काउंटर बनाने के लिए विभिन्न हैक हैं जो आप यहां पा सकते हैं , लेकिन सावधान रहें ये बेहोश दिल के लिए नहीं हैं।


6
आप अभी भी shift9 से अधिक ... और समान रूप से दिखने वाले कोड की 10 पंक्तियाँ गिनने के लिए उपयोग कर सकते हैं ।
जॉय

19

:getargcनीचे दिया गया कार्य वह हो सकता है जिसकी आप तलाश कर रहे हैं।

@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

यह मूल रूप से सूची में एक बार पुनरावृत्ति करता है (जो फ़ंक्शन के लिए स्थानीय है, इसलिए बदलाव मुख्य कार्यक्रम में वापस सूची को प्रभावित नहीं करेंगे), उन्हें गिनते हुए जब तक यह बाहर नहीं निकलता।

यह एक निफ्टी ट्रिक का भी उपयोग करता है, जो फ़ंक्शन द्वारा सेट किए जाने वाले रिटर्न चर का नाम देता है।

मुख्य कार्यक्रम सिर्फ यह बताता है कि इसे कैसे कॉल किया जाए और तर्कों को बाद में यह सुनिश्चित किया जाए कि वे अछूते हैं:

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"

आप इसके आधार पर प्रवाह को कैसे बदल सकते हैं? (एक अलग सवाल हो सकता है, लेकिन मुझे लगता है कि एक छोटा उदाहरण यहां भी बहुत सुविधाजनक होगा!)
n611x007

@ n611x007 जहां echo Count is %argc%आप अपना स्वयं का कोड डालेंगे, जो यह जांच सकता है कि क्या गिनती उचित है और फिर आगे बढ़ें।
केनी

7

इसे इस्तेमाल करे:

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

6
इस उत्तर के किसी भी तरह से अलग है @nimrod एक ...?
नीले

1
nimrodm में @FerdinandBeyer द्वारा टिप्पणी की जाँच करें। नीचे नहीं जा रहा है क्योंकि आपके पास 21 प्रतिनिधि 8 हैं
n611x007

6

यदि तर्कों की संख्या एक सटीक संख्या (कम या 9 के बराबर) होनी चाहिए, तो यह जांचने का एक सरल तरीका है:

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

आकार और पठनीयता की कीमत पर shiftया तो या एक forचक्र का उपयोग करने से बचा जाता है।

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

आउटपुट:

count_cmdline_args.bat testing more_testing arg3 another_arg

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

संपादित करें: "ट्रिक" का यहाँ उपयोग किया जाता है:

  1. एक स्ट्रिंग का निर्माण करना जो वर्तमान में मूल्यांकन किए गए कमांड-लाइन तर्क चर (अर्थात "% 1", "% 2" आदि) का उपयोग करके एक स्ट्रिंग का उपयोग करता है जिसमें एक प्रतिशत वर्ण ( %%) और arg_idxप्रत्येक लूप पुनरावृत्ति पर एक काउंटर चर होता है।

  2. उस स्ट्रिंग को एक चर में संग्रहीत करना curr_arg_label

  3. उस स्ट्रिंग ( !curr_arg_label!) और रिटर्न वैरिएबल के नाम ( curr_arg_value) दोनों को एक आदिम उपप्रोग्राम में पास करना get_value

  4. उपप्रोग्राम में इसके पहले तर्क के ( %1) मान का उपयोग असाइनमेंट के बाईं ओर ( set) और इसके दूसरे तर्क के ( %2) मूल्य पर दाईं ओर किया जाता है। हालाँकि, जब दूसरा उपप्रोग्राम का तर्क पास हो जाता है, तो इसे मुख्य प्रोग्रामर के कमांड-लाइन तर्क के कमांड दुभाषिया के मूल्य में हल किया जाता है। यही है, जो पारित किया गया है, उदाहरण के लिए, "% 4" नहीं, लेकिन चौथे कमांड-लाइन तर्क चर का जो भी मूल्य है (नमूना उपयोग में "एक और_गर्ग")।

  5. फिर रिटर्न वैरिएबल ( curr_arg_value) के रूप में उपप्रोग्राम को दिए गए चर को अपरिभाषित होने के लिए परीक्षण किया जाता है, जो कि वर्तमान में मूल्यांकन किए गए कमांड-लाइन तर्क के अनुपस्थित होने पर होता है। प्रारंभ में यह खाली वर्ग कोष्ठक में वर्ग कोष्ठक में लिपटे हुए रिटर्न वैरिएबल के मूल्य की तुलना थी (जो कि मुझे परीक्षण कार्यक्रम या उपप्रोग्राम तर्कों का एकमात्र तरीका है, जिसमें उद्धरण शामिल हो सकते हैं और परीक्षण-और-त्रुटि चरण से एक अनदेखा बचे हुए थे) लेकिन के बाद से यह कैसे तय किया गया था।


1
हालांकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन यह समस्या का हल कैसे और / या इसके बारे में अतिरिक्त संदर्भ प्रदान करता है, इससे उत्तर के दीर्घकालिक मूल्य में सुधार होगा।
Thewaywewere

@thewaywewere धन्यवाद, मैं यह भूल जाता हूं कि बहुत से लोगों के लिए (बहुसंख्यक होने की संभावना है) "आत्म-व्याख्यात्मक" कोड के बजाय एक पाठ विवरण रखना बेहतर है।
फेन-फायर

@ फेन-फायर सिवाय इसके कि कोड आत्म व्याख्यात्मक नहीं है।
Loduwijk

1

आखिरी जवाब अब दो साल पहले था, लेकिन मुझे नौ से अधिक कमांड लाइन तर्कों के लिए एक संस्करण की आवश्यकता थी। हो सकता है कोई दूसरा भी करे ...

@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

समाधान पहली 19 पंक्तियाँ हैं और सभी तर्कों को एक सी-सी शैली में चर में परिवर्तित करती हैं। अन्य सभी सामान सिर्फ परिणाम की जांच करते हैं और स्थानीय आर्ग में रूपांतरण दिखाते हैं। आप किसी भी फ़ंक्शन में सूचकांक द्वारा तर्कों का संदर्भ दे सकते हैं।


0

एक मजबूत समाधान एक करने के लिए उनकी गिनती को सौंपने के लिए है सबरूटीन के साथ आमंत्रण call; सबरूटीन gotoएक लूप का अनुकरण करने के लिए कथनों का उपयोग करता है जिसमें 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.