배치 파일-명령 줄 인수 수


99

일부 셸 스크립트를 배치 파일로 변환하기 만하면 찾을 수없는 것 하나가 있습니다. 이것은 명령 줄 인수 수의 단순한 개수입니다.

예. 당신이 가지고 있다면:

myapp foo bar

쉘에서 :

  • $ #-> 2
  • $ *-> foo 바
  • $ 0-> 마이 앱
  • $ 1-> foo
  • $ 2-> 바

일괄

  • ?? -> 2 <---- 무슨 명령?!
  • % *-> foo 바
  • % 0-> myapp
  • % 1-> foo
  • % 2-> 막대

그래서 주변을 둘러 보았고 잘못된 지점을 찾고 있거나 장님이지만 전달 된 명령 줄 인수의 수를 계산하는 방법을 찾을 수없는 것 같습니다.

배치 파일에 대한 쉘의 "$ #"과 유사한 명령이 있습니까?

추신. 내가 찾은 가장 가까운 것은 % 1s를 반복하고 'shift'를 사용하는 것이지만 나중에 스크립트에서 % 1, % 2 등을 참조해야하므로 좋지 않습니다.


당신의 문자열은 2 myapp foo bar?
PsychoData 2014

2
조언 : sh를 BAT로 변환하지 마십시오. 대신 cygwin을 다운로드하고 대신 사용하십시오. 즉, sh 스크립트는 Windows 시스템에서 작동합니다. 모든 sh를 BAT로 번역 할 필요가 없습니다!
Marty McGowan 2015

답변:


104

인터넷 검색을 통해 wikibooks 에서 다음과 같은 결과를 얻을 수 있습니다 .

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
shift똑같이 보이는 코드 10 줄 없이도 9 개 이상을 셀 수 있습니다 .
Joey

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 2013-08-23

@ n611x007 여기서 echo Count is %argc%해당 카운트가 적절한 지 확인한 다음 계속 진행할 수있는 자신의 코드를 삽입합니다.
kenny


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"가 아니라 네 번째 명령 줄 인수 변수가 보유하는 값 (샘플 사용에서 "another_arg")입니다.

  5. 그런 다음 반환 변수 ( curr_arg_value) 로 서브 프로그램에 제공된 변수 가 정의되지 않았는지 테스트합니다. 이는 현재 평가 된 명령 줄 인수가 없으면 발생합니다. 처음에는 대괄호로 묶인 반환 변수의 값을 빈 대괄호로 비교했습니다 (이는 따옴표를 포함 할 수 있고 시행 착오 단계에서 간과 된 테스트 프로그램 또는 하위 프로그램 인수에 대해 제가 아는 유일한 방법입니다). 그 이후로 지금의 상태로 고정되었습니다.


1
이 코드가 질문에 답할 수 있지만 문제를 해결하는 방법 및 / 또는 이유에 대한 추가 컨텍스트를 제공하면 답변의 장기적인 가치가 향상됩니다.
thewaywewere

@thewaywere 감사합니다. 많은 사람들 (아마 대다수)에게 "자세한"코드 대신 텍스트 설명을 갖는 것이 더 낫다는 사실을 계속 잊고 있습니다.
FEN-화재

코드가 자명하지 않다는 점을 제외하고 @ fen-fire.
Loduwijk

1

마지막 대답은 2 년 전 이었지만 9 개 이상의 명령 줄 인수를위한 버전이 필요했습니다. 다른 사람도 할 수 있습니다 ...

@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 줄이며 모든 인수를 c와 유사한 스타일의 변수로 변환합니다. 다른 모든 것은 결과를 조사하고 로컬 인수로의 변환을 보여줍니다. 모든 함수에서 인덱스로 인수를 참조 할 수 있습니다.


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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.