programing

CMD.EXE(Windows Command Interpreter)는 스크립트를 어떻게 구문 분석합니까?

closeapi 2023. 5. 31. 15:55
반응형

CMD.EXE(Windows Command Interpreter)는 스크립트를 어떻게 구문 분석합니까?

Windows Command Interpreter에서 실행할 배치 스크립트를 작성하는 방법에 대한 유용한 도움말을 제공하는 ss64.com 를 우연히 발견했습니다.

그러나 배치 스크립트의 문법, 사물이 확장되거나 확장되지 않는 방법, 사물을 탈출하는 방법에 대한 좋은 설명을 찾지 못했습니다.

다음은 제가 해결하지 못한 샘플 질문입니다.

  • 견적 시스템은 어떻게 관리됩니까?는 TinyPerl 대본을 만들었습니다.
    (foreach $i (@ARGV) { print '*' . $i ; }), 이것을 컴파일하고 다음과 같이 불렀습니다.
    • my_script.exe "a ""b"" c"은 력은입니다.*a "b*c
    • my_script.exe """a b c"""출력하다, 출력*"a*b*c"
  • 내부는 어떻습니까?echo명령작?안에 입니까?해당 명령 내에서 확장되는 것은 무엇입니까?
  • 제가 야하해이유는사를 ?for [...] %%I파일 스크립트에서, 그러나for [...] %I대화형 세션에서?
  • 탈출 캐릭터는 무엇이고, 어떤 맥락에서?퍼센트 기호를 피하는 방법은?예를 들어, 어떻게 반향할 수 있습니까?%PROCESSOR_ARCHITECTURE%문자 그대로?나는 그것을 발견했습니다.echo.exe %""PROCESSOR_ARCHITECTURE%효과가 있습니다. 더 나은 해결책이 있습니까?
  • 어떻게 쌍을 구성합니까?%일치? 예:
    • set b=a,echo %a %b% c%%a a c%
    • set a =b,echo %a %b% c%bb% c%
  • 변수에 큰따옴표가 포함된 경우 변수가 명령에 단일 인수로 전달되도록 하려면 어떻게 해야 합니까?
  • 사용 시 변수는 어떻게 저장됩니까?set명령?예를 들어, 제가 한다면요.set a=a" b그리고 나서.echo.%a%알겠습니다a" b가 하만사경우할용을 한다면,echo.exe에서 UnxUtils, .a b는 왜?%a%다른 방식으로 확장합니까?

우리는 배치 스크립트의 문법을 조사하기 위해 실험을 수행했습니다.배치 모드와 명령줄 모드 간의 차이점도 조사했습니다.

배치 선 구문 분석기:

다음은 배치 파일 줄 구문 분석기의 단계에 대한 간략한 개요입니다.

0단계) 라인 읽기:

1단계) 백분율 확장:

2단계) 특수 문자 처리, 토큰화 및 캐시된 명령 블록 구축:이 프로세스는 따옴표, 특수 문자, 토큰 구분 기호 및 캐럿 이스케이프 등의 영향을 받는 복잡한 프로세스입니다.

3단계) 명령 블록이 시작되지 않은 경우에만 구문 분석된 명령 에코@ECHO는 이전 단계를 시작할 때 켜졌습니다.

4단계) 가변 확장의 경우:FOR 명령이 활성화되고 DO 후 명령이 처리되는 경우에만 해당됩니다.

5단계) 확장 지연:지연 확장을 사용하도록 설정한 경우

5.3단계) 파이프 처리:명령이 파이프의 양쪽에 있는 경우에만

5.5단계) 리디렉션 실행:

6단계) CALL 처리/CARET 배가:명령 토큰이 CALL인 경우에만

7단계) 실행:명령이 실행됩니다.


각 단계에 대한 세부 정보는 다음과 같습니다.

아래에 설명된 단계는 배치 파서 작동 방식에 대한 모델일 뿐입니다.실제 cmd.exe 내부는 이러한 단계를 반영하지 않을 수 있습니다.그러나 이 모델은 배치 스크립트의 동작을 예측하는 데 효과적입니다.

0단계) 라인 읽기: 먼저 입력 라인 읽기<LF>.

  • 때 명어로구분행을때읽을할석문,<Ctrl-Z>(0x1A)는 다음과 같이 읽힙니다.<LF>라인피드 0x0A)
  • 또는 :label, :를 때 : GOTO <Ctrl-Z>자체로 처리됨 - 로 변환되지 않음<LF>

1단계) 백분율 확장:

  • 블더.%% 단로대됨으로 됩니다.%
  • 인수 확장(%*,%1,%2아래)
  • ▁▁expansion장%var%var가 존재하지 않으면 nothing으로 대체합니다.
  • 은 첫 번째 선이 에서 .<LF>에 없는%var%
  • 자세한 설명은 dbenham Same 스레드의 첫 번째 절반을 참조하십시오. 백분율 단계

2단계) 특수 문자 처리, 토큰화 및 캐시된 명령 블록 구축:이 프로세스는 따옴표, 특수 문자, 토큰 구분 기호 및 캐럿 이스케이프 등의 영향을 받는 복잡한 프로세스입니다.다음은 이 프로세스의 근사치입니다.

이 단계에서 중요한 개념이 있습니다.

  • 토큰은 단위로 처리되는 문자 문자열입니다.
  • 토큰은 토큰 구분 기호로 구분됩니다. 토큰 기호는 " 표토큰구기다같다습니음과"입니다.<space> <tab> ; , = <0x0B> <0x0C>그리고.<0xFF>
    토큰 기호는됩니다. 기호 에는 빈 . 토큰 구분 기호 사이에는 빈 토큰이 없습니다.
  • 따옴표로 묶은 문자열에는 토큰 구분 기호가 없습니다.따옴표로 묶인 전체 문자열은 항상 단일 토큰의 일부로 처리됩니다.단일 토큰은 따옴표로 묶인 문자열과 따옴표로 묶이지 않은 문자의 조합으로 구성될 수 있습니다.

문맥에 이 수 .<CR> ^ ( @ & | < > <LF> <space> <tab> ; , = <0x0B> <0x0C> <0xFF>

왼쪽에서 오른쪽으로 각 문자를 봅니다.

  • 한다면<CR>그런 다음 마치 없었던 것처럼 제거합니다(이상한 리디렉션 동작 제외).
  • 캐럿인 경우(^), 다음 문자는 이스케이프되고 이스케이프되는 캐럿은 제거됩니다.특별한 를 잃습니다 (단, 이케이단특의잃다습니미를별한모프된든스문자는,<LF>).
  • 인용문인 경우("를 전환합니다.), 따표플전환니다합를래옴그▁),다니전▁toggle합환▁the따.견적 플래그가 활성화된 경우에만"그리고.<LF>특별합다니. 때까지 모든 를 잃게 .다음 따옴표 플래그가 해제될 때까지 다른 모든 문자는 특별한 의미를 잃게 됩니다.마감 따옴표를 벗어날 수 없습니다.따옴표로 묶인 모든 문자는 항상 동일한 토큰 내에 있습니다.
  • <LF>항상 따옴표 플래그를 끕니다.문맥에 은 절대로 을 바꾸지 않습니다.<LF>.
    • 이스케이프됨<LF>
      • <LF>을 벗었습니다.
      • 다음 문자는 이스케이프됩니다.행 버퍼의 끝에 있는 경우 다음 행은 다음 문자를 이스케이프하기 전에 단계 1 및 1.5에서 읽고 처리되며 현재 행에 추가됩니다.다음 캐릭터가.<LF>그런 다음 이 프로세스가 재귀적이지 않음을 의미하는 리터럴로 처리됩니다.
    • 하지 못한 사람<LF>괄호 안에 없는
      • <LF>제거되고 현재 라인의 구문 분석이 종료됩니다.
      • 줄 버퍼의 나머지 문자는 무시됩니다.
    • 하지 못한 사람<LF>괄호 안의 FOR 내
      • <LF>는 로변됩다로 됩니다.<space>
      • 행 버퍼 끝에 있는 경우 다음 행을 읽고 현재 행에 추가합니다.
    • 하지 못한 사람<LF>괄호로 묶은 명령 블록 내에서
      • <LF>는 로변됩다니로 됩니다.<LF><space> 리고그고.<space>는 명령 블록의 다음 줄의 일부로 처리됩니다.
      • 행 버퍼 끝에 있는 경우 다음 행이 읽혀지고 공백에 추가됩니다.
  • 특별한 캐릭터 중 하나가& | <또는>파이프, 명령 연결 및 리디렉션을 처리하기 위해 이 지점에서 줄을 분할합니다.
    • pipe)의|), 각 5의 명령 블록
    • &,&&또는||명령 연결, 연결의 각 측면은 별도의 명령으로 처리됩니다.
    • <,<<,>또는>>구문 한 후 명령어 .redirection, redirection의 합니다.리디렉션 절은 선택적 파일 핸들 숫자, 리디렉션 연산자 및 리디렉션 대상 토큰으로 구성됩니다.
      • 리디렉션 연산자 앞에 오는 토큰이 이스케이프되지 않은 단일 숫자인 경우, 해당 숫자는 리디렉션할 파일 핸들을 지정합니다.핸들 토큰을 찾을 수 없으면 출력 리디렉션 기본값은 1(stdout)이고 입력 리디렉션 기본값은 0(stdin)입니다.
  • 첫을 이동하기 전이 " " " " " " " " " " (" " " " " " " " " " " " " 로 합니다." " " " " " " " " 로 시작합니다.@ 다음에 그음에다.@특별한 의미가 있습니다.(@다른 맥락에서 특별하지 않음)
    • 한 스셜페셜▁the@제거됩니다.
    • ECHO가 ON인 경우 이 명령은 이 라인의 다음 연결된 명령과 함께 단계 3 에코에서 제외됩니다.에 약에만.@ 오전입다니픈 앞에 .(그러면 전체 괄호 블록이 단계 3 에코에서 제외됩니다.
  • 프로세스 괄호(여러 줄에 걸친 복합 문에 제공):
    • 토큰을 에는 " " " " 입니다.(특별하지 않습니다.
    • 을 찾고 때 검색된 명령어 토큰이 ( 새 의 카운터를 .
    • 안의 보다 클 에는 0이 됩니다.)복합 문을 종료하고 괄호 카운터를 줄입니다.
    • 행 끝에 도달하고 괄호 카운터가 0보다 클 경우 다음 행이 복합 문에 추가됩니다(단계 0으로 다시 시작).
    • 안의 , 그 다음은 0입니다.) 한 기능REM토큰 구분 기호, 특수 문자, 새 줄 또는 파일 끝 바로 뒤에 오는 문
      • 다음을 제외한 모든 특수 문자는 의미를 잃습니다.^선 연결 가능)
      • 논리적 행의 끝에 도달하면 전체 "명령"이 삭제됩니다.
  • 각 명령은 일련의 토큰으로 구문 분석됩니다.첫 번째 토큰은 항상 명령 토큰으로 처리됩니다(특수 후).@제거되고 리디렉션이 끝으로 이동됨).
    • 명령 토큰 이전의 선행 토큰 구분 기호가 제거됨
    • 을 구문 할 때, " " "는 " " 입니다.(는 표준 기호 토큰 합니다.
    • 이후 토큰의 처리는 명령에 따라 달라집니다.
  • 대부분의 명령은 명령 토큰 뒤의 모든 인수를 단일 인수 토큰으로 연결합니다.모든 인수 토큰 구분 기호가 보존됩니다.인수 옵션은 일반적으로 7단계까지 구문 분석되지 않습니다.
  • IF, FOR 및 REM의 세 가지 명령이 특수 처리됩니다.
    • 두개 세 . IF는 독립적으로 처리됩니다.IF 구성의 구문 오류로 인해 치명적인 구문 오류가 발생합니다.
      • 비교 연산은 단계 7까지 이어지는 실제 명령입니다.
        • 모든 IF 옵션은 2단계에서 완전히 구문 분석됩니다.
        • 연속된 토큰 구분 기호는 단일 공간으로 축소됩니다.
        • 비교 연산자에 따라 하나 또는 두 개의 값 토큰이 식별됩니다.
      • True 명령 블록은 조건 다음 명령 집합이며 다른 명령 블록과 마찬가지로 구문 분석됩니다.ELSE를 사용하려면 True 블록을 괄호로 묶어야 합니다.
      • 옵션인 False 명령 블록은 ELSE 다음 명령 집합입니다.다시 말하지만, 이 명령 블록은 정상적으로 구문 분석됩니다.
      • 참 및 거짓 명령 블록은 이후 단계로 자동으로 흐르지 않습니다.이들의 후속 처리는 7단계에 의해 제어됩니다.
    • FO는 DO 후에 둘로 나뉩니다.FOR 구문의 구문 오류로 인해 치명적인 구문 오류가 발생합니다.
      • DO를 통한 부분은 단계 7을 통해 계속 흐르는 실제 FOR 반복 명령입니다.
        • 모든 FOR 옵션은 2단계에서 완전히 구문 분석됩니다.
        • 안에 은 IN을 취급합니다.<LF>~하듯이<space>IN 절을 구문 분석한 후에는 모든 토큰이 함께 연결되어 단일 토큰을 형성합니다.
        • 연속적으로 이스케이프되지 않거나 따옴표로 묶이지 않은 토큰 구분 기호는 DO를 통해 FOR 명령 전체에 걸쳐 단일 공간으로 축소됩니다.
      • DO 다음 부분은 정상적으로 구문 분석되는 명령 블록입니다.DO 명령 블록의 후속 처리는 단계 7의 반복에 의해 제어됩니다.
    • 단계 2에서 감지된 REM은 다른 모든 명령과 다르게 처리됩니다.
      • 하나의 인수 토큰만 구문 분석됩니다. 파서는 첫 번째 인수 토큰 뒤의 문자를 무시합니다.
      • REM 명령은 페이즈 3 출력에 나타날 수 있지만 명령은 실행되지 않으며 원래 인수 텍스트가 반향됩니다. 이스케이프는 제거되지 않습니다(예:
        • 이스케이프되지 않은 것으로 끝나는 인수 토큰이 하나만 있는 경우^그러면 행이 종료되고 인수 토큰이 버려지며 후속 행이 구문 분석되어 REM에 추가됩니다.두 개 있거나 가 "" " " " " 토 두 개 이 있 거 나 마 때 반 아 복 니 됩 다 지 까 닐 문 가 자 막 지 큰 이 상 니 다 반 됩 ▁this ▁is 복 ▁there ▁not , ▁until 때 ▁repeats ▁or ▁the 지^.
  • 이 명토큰다음시로 :그리고 이것은 2단계의 첫 번째 라운드입니다(6단계의 CALL로 인한 재시작이 아님).
    • 토큰은 일반적으로 실행되지 않은 레이블로 처리됩니다.
      • 줄의 나머지 부분은 구문 분석됩니다.),<,>,&그리고.|더 이상 특별한 의미가 없습니다.줄의 전체 나머지 부분은 "명령" 레이블의 일부로 간주됩니다.
      • ^계속 특별합니다. 즉, 라인 연속을 사용하여 후속 라인을 레이블에 추가할 수 있습니다.
      • 괄호 안에 있는 실행되지 않은 레이블은 다음 줄에 명령이나 실행된 레이블이 바로 뒤따르지 않는 한 치명적인 구문 오류가 발생합니다.
        • (실행되지 않은 레이블 뒤에 오는 첫 번째 명령에 대해 더 이상 특별한 의미가 없습니다.
      • 레이블 구문 분석이 완료된 후 명령이 중단됩니다.라벨에 대한 후속 단계가 발생하지 않습니다.
    • 단계 2에서 발견된 레이블이 단계 7을 통해 구문 분석을 계속하는 실행된 레이블로 처리될 수 있는 세 가지 예외가 있습니다.
      • 레이블 토큰 앞에 리디렉션이 있고 다음이 있습니다.|파이프 또는&,&&또는||라인의 명령 연결입니다.
      • 레이블 토큰 앞에 리디렉션이 있으며 명령은 괄호로 묶인 블록 안에 있습니다.
      • 레이블 토큰은 괄호 안에 있는 줄의 첫 번째 명령이며, 위의 줄은 실행되지 않은 레이블로 끝납니다.
    • 단계 2에서 실행된 라벨이 발견되면 다음이 발생합니다.
      • 라벨, 인수 및 리디렉션은 단계 3의 에코 출력에서 모두 제외됩니다.
      • 라인에 연결된 이후의 모든 명령은 완전히 구문 분석되고 실행됩니다.
    • 실행된 레이블에 대한 자세한 내용을 참조하십시오.실행되지 않은 라벨, https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405 참조

3단계) 명령 블록이 시작되지 않은 경우에만 구문 분석된 명령 에코@ECHO는 이전 단계를 시작할 때 켜졌습니다.

4단계) 가변 확장의 경우:FOR 명령이 활성화되고 DO 후 명령이 처리되는 경우에만 해당됩니다.

  • 를 FOR 변수로 했습니다.%%X안으로%X명령줄에 단계 1에 대한 백분율 확장 규칙이 다릅니다.에서 이이명이사이용유다니를 입니다.%X은 그나배파일을 사용합니다.%%X변수의 경우.
  • 하지만 FOR 변수 이름은 대소문자를 구분합니다.~modifiers대소문자를 구분하지 않습니다.
  • ~modifiers변수 이름보다 우선합니다. 과같은문자있경을우가음다 에 오는 라면.~는 수식어이자 유효한 변수 이름이며, 변수 이름에 대해 활성화된 후속 문자가 존재하며, 문자는 수식어로 해석됩니다.
  • FOR 변수 이름은 전역이지만 DO 절의 컨텍스트 내에서만 사용됩니다.FOR DO 절 내에서 루틴이 호출되면 FOR 변수는 호출된 루틴 내에서 확장되지 않습니다.그러나 루틴에 고유한 FOR 명령이 있으면 현재 정의된 모든 FOR 변수가 내부 DO 명령에 액세스할 수 있습니다.
  • FOR 변수 이름은 중첩된 FOR 내에서 재사용할 수 있습니다.내부 FOR 값이 우선하지만 내부 FOR 값이 닫히면 외부 FOR 값이 복원됩니다.
  • 이 단계를 시작할 때 ECHO가 ON이었던 경우 FOR 변수를 확장한 후 3) 단계를 반복하여 구문 분석된 DO 명령을 표시합니다.

이때부터 단계 2에서 식별된 각 명령은 개별적으로 처리됩니다.
다음 명령으로 이동하기 전에 한 명령에 대해 단계 5 ~ 7이 완료됩니다.

5단계) 확장 지연:지연 확장이 설정된 경우에만 명령이 파이프의 양쪽에 있는 괄호 블록에 있지 않으며 명령이 "없음" 배치 스크립트(괄호, CALL, 명령 연결 또는 파이프가 없는 스크립트 이름)가 아닙니다.

  • 명령의 각 토큰은 개별적으로 지연된 확장을 위해 구문 분석됩니다.
    • 대부분의 명령은 두 개 이상의 토큰(명령 토큰, 인수 토큰 및 각 리디렉션 대상 토큰)을 구문 분석합니다.
    • FOR 명령은 IN 절 토큰만 구문 분석합니다.
    • IF 명령은 비교 연산자에 따라 하나 또는 두 개의 비교 값만 구문 분석합니다.
  • 구문 분석된 토큰에 "" "" "" "" "" "" ""가 합니다.!그렇지 않은 경우 토큰은 구문 분석되지 않습니다. 중요:^성격. 토에다포되어 있는 .!그런 다음 왼쪽에서 오른쪽으로 각 문자를 스캔합니다.
    • 캐럿인경우(우경▁if캐▁it^의미가 , 됩니다.
    • 느낌표인 경우 다음 느낌표를 검색하고 변수 값으로 확장합니다(더 이상 주의 사항이 관찰되지 않음).
      • 오프닝! 하로접다니로 축소됩니다.!
      • 짝을 이루지 않은 짝을이못한모나든것지머지루▁▁un▁any것든모.! 제거되었습니다.
    • 를 확장하는 이상 가 감지되지 않기 합니다(심지어는 특문자더안합심않때이변것확니다수전는은는장하지어를기수서계단에문가에이).<CR>또는<LF>)
    • 자세한 설명은 dbenham same thread의 두 번째 절반을 읽어보십시오 - 느낌표 단계.

5.3단계) 파이프 처리:명령이 파이프의 양쪽에 있는 경우에만
파이프의 각 측면은 독립적이고 비동기적으로 처리됩니다.

  • 이 cmd에는 cmd.exe 파일을 새됩니다.%comspec% /S /D /c" commandBlock"따라서 명령 블록은 단계적으로 재시작되지만 이번에는 명령줄 모드로 재시작됩니다.
    • 괄호로 묶은 명령 블록의 경우 모두<LF>변환전 사명령용하여로 <space>& .<LF>옷을 벗었습니다.
  • 파이프 명령에 대한 처리는 이것으로 끝입니다.
  • 자세한 내용은 코드 블록 내부에서 지연된 확장이 실패하는 이유는 무엇입니까?를 참조하십시오.파이프 구문 분석 및 처리에 대한 자세한 내용

5.5단계) 리디렉션 실행:단계 2에서 검색된 리디렉션이 이제 실행됩니다.

6단계) CALL 처리/CARET 배가:명령 토큰이 CALL이거나 처음 발생하는 표준 토큰 구분 기호 앞의 텍스트가 CALL인 경우에만 해당됩니다.CALL이 더 큰 명령 토큰에서 구문 분석되면 계속하기 전에 사용되지 않은 부분이 인수 토큰 앞에 추가됩니다.

  • 로 묶이지 않은 합니다./?토큰 내에서 찾을 수 있는 경우 6단계를 중단하고 7단계로 진행합니다. 여기서 HELP for CALL이 인쇄됩니다.
  • 번째 첫 번 항 목 제 거 째를 합니다.CALL의 CALL을 수 .
  • 모든 주의사항을 두 배로 늘립니다.
  • 단계 1, 1.5 및 2를 다시 시작하지만 단계 3은 계속하지 않음
    • 따옴표로 묶지 않는 한 두 배의 캐럿은 다시 하나의 캐럿으로 줄어듭니다.하지만 불행히도 인용된 의료 서비스는 두 배로 증가했습니다.
    • 1단계는 약간의 변화 - 1.2 또는 1.3단계의 확장 오류로 CALL이 중단되지만 오류는 치명적이지 않습니다 - 배치 처리가 계속됩니다.
    • 2단계 작업이 약간 변경되었습니다.
      • 단계 2의 첫 번째 라운드에서 탐지되지 않은 인용되지 않은, 탈출되지 않은 새로 나타나는 리디렉션이 탐지되지만, 실제로 리디렉션을 수행하지 않고 제거됩니다(파일 이름 포함).
      • 줄 끝에 따옴표로 묶이지 않고 이스케이프되지 않은 새로 나타나는 캐럿은 줄을 계속하지 않고 제거됩니다.
      • 다음 중 하나라도 감지되면 오류 없이 CALL이 중단됩니다.
        • 되지 않은,되지 않은, 새롭게 한, 탈지되은않않지용등새장로은인되출▁newly▁un등장▁appearing,새로▁un은않.&또는|
        • 따옴표로 묶이지 않고 않은 결과명토따로 합니다.(
        • 첫 은 된이시 CALL후작첫된번째로 합니다.@
      • IF 또는하고 다음 합니다. " " " " IF " " " " " 입니다.IF또는FOR는 내부 또는 외부 명령으로 인식되지 않습니다.
      • 이 토큰이 물론결토이다음으로 .:.
  • 결과 명령 토큰이 CALL이면 6단계를 다시 시작합니다(더 이상 CALL이 없을 때까지 반복).
  • 결과 명령 토큰이 배치 스크립트 또는 :label인 경우 CALL의 실행은 단계 6의 나머지 부분에서 완전히 처리됩니다.
    • CALL이 완료되면 올바른 위치에서 실행을 재개할 수 있도록 콜 스택의 현재 배치 스크립트 파일 위치를 누릅니다.
    • %0, %1, %2, ...을(를) 설정합니다.CALL에 대한 %N 및 %* 인수 토큰(결과 토큰 모두 사용)
    • 이 령명토다로 :,그리고나서
      • 5단계를 다시 시작합니다.이는 레이블이 CALLED인 항목에 영향을 미칠 수 있습니다.그러나 %0 등의 토큰이 이미 설정되었기 때문에 CALLed 루틴으로 전달되는 인수는 변경되지 않습니다.
      • 서브루틴의 부분에 label ). 를 참조하십시오.GOTO는 과 같습니다(label: label 있다토른큰은시무는레수다배니합치시이블을의틴에부분작실일루 파 GOTO 작동 방식에 대한 규칙은 7단계를 참조하십시오.
    • 그렇지 않으면 지정된 배치 스크립트로 제어 권한을 전송합니다.
    • : 실행은 /B 또는 되며, 파일 됩니다.CALLed : CALLED : EXIT /B 행달때계까도지되며속할끝에은파라재실스팝이위때, 개저됩이다니파행서에치일된장고되업이택벨는크또립트의스일는실또▁execution▁orlabel▁/call▁continues재실▁:b▁position위▁is▁script▁the파개이에치됩일▁:▁call이때
      CALLed 또는 7에 .단계는 CALLed 스크립트 또는 :label에 대해 실행되지 않습니다.
  • 그렇지 않으면 6단계의 결과는 실행을 위해 7단계로 넘어갑니다.

7단계) 실행:명령이 실행됩니다.

  • 7.1 - 내부 명령 실행 - 명령 토큰이 따옴표로 묶인 경우 이 단계를 건너뜁니다.그렇지 않으면 내부 명령을 구문 분석하여 실행합니다.
    • 따옴표로 묶이지 않은 명령 토큰이 내부 명령을 나타내는지 여부를 확인하기 위해 다음 테스트를 수행합니다.
      • 명령 토큰이 내부 명령과 정확히 일치하는 경우 실행합니다.
      • 이 처음 에 명령 토큰을 .+ / [ ] <space> <tab> , ;또는=
        앞의 텍스트가 내부 명령인 경우 해당 명령을 기억합니다.
        • 명령줄 모드에서 또는 명령이 괄호로 묶인 블록, 참 또는 거짓 명령 블록, FORDO 명령 블록 또는 명령 연결과 관련된 경우 내부 명령을 실행합니다.
        • 그렇지 않으면(배치 모드의 독립 실행형 명령이어야 함) 기본 이름이 원래 명령 토큰과 일치하는 .COM, .EXE, .BAT 또는 .CMD 파일에 대해 현재 폴더와 PATH를 검색합니다.
          • 첫 번째 일치 파일이 .BAT 또는 .CMD이면 7.3.exe로 이동하여 해당 스크립트를 실행합니다.
          • 그렇지 않으면(일치 항목을 찾을 수 없거나 첫 번째 일치 항목이 .EXE 또는 .COM) 기억된 내부 명령을 실행합니다.
      • 이 처음 에 명령 토큰을 .. \또는:
        명령어가 7.2 의텍스내명부령아 7.2 합니다로 합니다.
        그렇지 않으면 앞의 텍스트가 내부 명령일 수 있습니다.이 명령을 기억하십시오.
      • 은 처음 .+ / [ ] <space> <tab> , ;또는=
        파일에 7.2 " 텍전트기가파존일경의경 7.2 "로 합니다.
        그렇지 않으면 기억된 내부 명령을 실행합니다.
    • 더 큰 명령 토큰에서 내부 명령을 구문 분석하면 명령 토큰의 사용되지 않은 부분이 인수 목록에 포함됩니다.
    • 명령 토큰이 내부 명령으로 구문 분석된다고 해서 성공적으로 실행되는 것은 아닙니다.각 내부 명령에는 인수와 옵션을 구문 분석하는 방법과 허용되는 구문에 대한 자체 규칙이 있습니다.
    • 모든 내부 명령은 다음과 같은 경우 해당 기능을 수행하는 대신 도움말을 인쇄합니다./?탐지되었습니다.대부분의 사람들/?인수에 표시되는 경우.및몇첫 토큰이 "ECHO " SET "로 합니다./?.
    • SET에는 몇 가지 흥미로운 의미가 있습니다.
      • 가 있는 에는 SET 명령어를 사용합니다.
        set "name=content" ignored --> value=content
        그런 다음 첫 번째 등호와 마지막 따옴표 사이의 텍스트가 내용으로 사용됩니다(첫 번째 등호와 마지막 따옴표 제외).마지막 따옴표 뒤의 텍스트는 무시됩니다.등호 뒤에 따옴표가 없으면 줄의 나머지 부분이 내용으로 사용됩니다.
      • SET 명령어에 이름 앞에 따옴표가 없는 경우
        set name="content" not ignored --> value="content" not ignored
        그런 다음 등수 뒤에 있는 줄의 전체 나머지 부분이 내용으로 사용됩니다(존재할 수 있는 모든 따옴표 포함).
    • IF 비교가 평가되며, 조건이 참인지 거짓인지에 따라 이미 구문 분석된 종속 명령 블록이 단계 5부터 처리됩니다.
    • FOR 명령의 IN 절은 적절하게 반복됩니다.
      • 이것이 명령 블록의 출력을 반복하는 FOR/F이면 다음과 같습니다.
        • IN 절은 CMD/C를 통해 새 cmd.exe 프로세스에서 실행됩니다.
        • 명령 블록은 전체 구문 분석 프로세스를 두 번째로 거쳐야 하지만 이번에는 명령줄 컨텍스트에서 수행됩니다.
        • ECHO는 ON으로 시작되고 지연된 확장은 일반적으로 비활성화 상태로 시작됩니다(레지스트리 설정에 따라 다름).
        • 자식 cmd.exe 프로세스가 종료되면 IN 절 명령 블록의 모든 환경 변경 내용이 손실됩니다.
      • 각 반복의 경우:
        • FOR 변수 값이 정의됩니다.
        • 그런 다음 이미 구문 분석된 DO 명령 블록이 단계 4부터 처리됩니다.
    • GOTO는 다음 논리를 사용하여 :label을 찾습니다.
      • 첫 번째 인수 토큰에서 레이블 구문 분석
      • 레이블의 다음 항목 검색
        • 현재 파일 위치에서 시작
        • 파일의 끝에 도달한 경우 파일의 처음으로 루프백하고 원래 시작 지점으로 계속 이동합니다.
      • 검색은 발견된 레이블의 첫 번째 위치에서 중지되고 파일 포인터는 레이블 바로 뒤에 있는 줄로 설정됩니다.이 시점부터 스크립트 실행이 다시 시작됩니다.성공적인 진정한 GOTO는 FOR 루프를 포함하여 구문 분석된 코드 블록을 즉시 중단합니다.
      • 레이블을 찾을 수 없거나 레이블 토큰이 없으면 GOTO가 실패하고 오류 메시지가 인쇄되고 콜 스택이 팝업됩니다.GOTO를 따르는 현재 명령 블록에서 이미 구문 분석된 명령이 여전히 실행되지만 CALLER의 컨텍스트(EXIT/B 뒤에 존재하는 컨텍스트)에서는 실행되지 않는 한 EXIT/B로 효과적으로 작동합니다.
      • 레이블 구문 분석 규칙에 대한 자세한 설명은 https://www.dostips.com/forum/viewtopic.php?t=3803 을 참조하고 레이블 검색 규칙은 https://www.dostips.com/forum/viewtopic.php?t=8988 을 참조하십시오.
    • Rename(이름 변경) 및 COPY(복사)는 모두 원본 경로와 대상 경로에 와일드카드를 사용할 수 있습니다.그러나 Microsoft는 특히 대상 경로에 대해 와일드카드가 어떻게 작동하는지 문서화하는 끔찍한 작업을 수행합니다.유용한 와일드카드 규칙 집합은 Windows RNAME 명령이 와일드카드를 해석하는 방법에서 찾을 수 있습니다.
  • 7.2 - 볼륨 변경 실행 - 명령 토큰이 따옴표로 시작하지 않고 정확히 2자이며 두 번째 문자가 콜론인 경우 볼륨을 변경합니다.
    • 모든 인수 토큰이 무시됩니다.
    • 첫 번째 문자로 지정한 볼륨을 찾을 수 없는 경우 오류와 함께 중단합니다.
    • 의 명 큰::을 정의하기 SUB를 한 합니다.::
      볼륨을 SUB를 하는 ::그러면 볼륨이 변경되고 레이블로 처리되지 않습니다.
  • 7.3 - 외부 명령 실행 - 그렇지 않으면 명령을 외부 명령으로 처리합니다.
    • 명령줄 모드에서 명령이 따옴표로 묶이지 않고 볼륨 사양, 공백으로 시작하지 않는 경우,,;,=또는+ 명령 때 끊습니다.<space> , ;또는=나머지를 인수 토큰 앞에 추가합니다.
    • 명령 토큰의 두 번째 문자가 콜론인 경우 첫 번째 문자로 지정된 볼륨을 찾을 수 있는지 확인합니다.
      볼륨을 찾을 수 없는 경우 오류와 함께 중단합니다.
    • 이 배치모서로 :그런 다음 7.4로 이동합니다.
      이 레블토큰다이로 하는 경우 하세요.::하는 데 한 에 이 할 수 .::.
    • 실행할 외부 명령을 식별합니다.
      • 이 프로세스는 현재 볼륨, 현재 디렉터리, PATH 변수, PATHEXT 변수 및/또는 파일 연결을 포함할 수 있는 복잡한 프로세스입니다.
      • 유효한 외부 명령을 식별할 수 없는 경우 오류와 함께 중단합니다.
    • 이 명줄모서로 :그런 다음 7.4로 이동합니다.
      이 " 명토큰다로시작않지한는오이"로 시작하지 않는 한 이전 에 이 하는 경우에 하십시오.::는 SUST의 할 때 합니다.::전체 명령 토큰은 외부 명령에 대한 유효한 경로입니다.
    • 7.3.exec - 외부 명령을 실행합니다.
  • 7.4 - 레이블 무시 - 명령 토큰이 다음으로 시작하는 경우 명령과 모든 인수를 무시합니다.:.
    7.2 및 7.3의 규칙에 따라 레이블이 이 지점에 도달하지 못할 수 있습니다.

명령줄 구문 분석기:

다음을 제외하고는 BatchLine-Parser와 같이 작동합니다.

1단계) 백분율 확장:

  • 아니요.%*,%1인수 확장 등
  • var가 정의되지 않은 경우%var%변경되지 않은 상태로 유지됩니다.
  • 특별한 취급은 없습니다.%%var=내용인 경우,%%var%%로 확장됨.%content%.

3단계) 구문 분석된 명령 에코

  • 이 작업은 단계 2 이후에는 수행되지 않습니다.FORDO 명령 블록에 대해서는 단계 4 이후에만 수행됩니다.

5단계) 지연된 확장: 지연된 확장이 활성화된 경우에만

  • var가 정의되지 않은 경우!var!변경되지 않은 상태로 유지됩니다.

7단계) 명령 실행

  • CALL 또는 GOTO: 라벨을 시도하면 오류가 발생합니다.
  • 7단계에서 이미 문서화된 것처럼, 실행된 라벨은 다른 시나리오에서 오류를 발생시킬 수 있습니다.
    • 일괄 실행된 레이블은 다음으로 시작하는 경우에만 오류가 발생할 수 있습니다.::
    • 명령줄 실행 레이블은 거의 항상 오류를 발생시킵니다.

정수 값 구문 분석

cmd.exe가 문자열의 정수 값을 구문 분석하는 다양한 컨텍스트가 있으며 규칙이 일관되지 않습니다.

  • SET /A
  • IF
  • %var:~n,m%(하위 문자열 확장 필요)
  • FOR /F "TOKENS=n"
  • FOR /F "SKIP=n"
  • FOR /L %%A in (n1 n2 n3)
  • EXIT [/B] n

이러한 규칙에 대한 자세한 내용은 규칙에서 CMD.EXE가 숫자를 구문 분석하는 방법을 확인할 수 있습니다.


cmd.exe 구문 분석 규칙을 개선하고자 하는 사용자는 DosTips 포럼에서 문제를 보고하고 제안할 수 있는 토론 주제가 있습니다.

Jan Erik (jeb) - 위상의 원저자이자 발견자
Dave Benham (dbenham) - 많은 추가 콘텐츠 및 편집

명령 창에서 명령을 호출할 때 명령줄 인수의 토큰화는 다음과 같이 수행되지 않습니다.cmd.exe(일명:"껍질").토큰화는 대부분 새로 형성된 프로세스의 C/C++ 런타임에 의해 수행되지만 반드시 그렇지는 않습니다. 예를 들어, 새 프로세스가 C/C++로 작성되지 않았거나 새 프로세스가 무시하기로 선택한 경우입니다.argv원시 명령줄을 처리합니다(예: GetCommandLine())).OS 수준에서 Windows는 토큰화되지 않은 명령줄을 단일 문자열로 새 프로세스에 전달합니다.대부분의 *nix 셸은 새로 형성된 프로세스에 인수를 전달하기 전에 일관되고 예측 가능한 방식으로 인수를 토큰화합니다.이 모든 것은 개별 프로그램이 종종 자신의 손으로 인수 토큰화를 수행하기 때문에 Windows(윈도우)의 여러 프로그램에서 서로 다른 인수 토큰화 동작을 경험할 수 있음을 의미합니다.

무정부 상태처럼 들리면, 일종의 무정부 상태입니다.그러나 많은 수의 윈도우 프로그램들이 마이크로소프트 C/C++ 런타임을 사용하기 때문에argvMSVCRT가 인수를 토큰화하는 방법을 이해하는 것이 일반적으로 유용할 수 있습니다.다음은 발췌한 내용입니다.

  • 인수는 공백 또는 탭으로 구분됩니다.
  • 큰따옴표로 둘러싸인 문자열은 포함된 공백에 관계없이 단일 인수로 해석됩니다.따옴표로 묶은 문자열을 인수에 포함할 수 있습니다.캐럿(^)은 이스케이프 문자 또는 구분 기호로 인식되지 않습니다.
  • 백슬래시 \" 앞에 큰따옴표가 있으면 문자 그대로 큰따옴표(")로 해석됩니다.
  • 백슬래시는 큰따옴표 바로 앞에 있지 않는 한 문자 그대로 해석됩니다.
  • 짝수 개의 백슬래시 뒤에 큰따옴표가 있으면 각 백슬래시 쌍(\)에 대해 하나의 백슬래시()가 Argv 배열에 배치되고 큰따옴표(")는 문자열 구분 기호로 해석됩니다.
  • 홀수의 백슬래시 뒤에 큰따옴표가 있으면 각 백슬래시 쌍(\)에 대해 하나의 백슬래시()가 Argv 배열에 배치되고 이중따옴표는 나머지 백슬래시에 의해 이스케이프 시퀀스로 해석되므로 문자 그대로 큰따옴표(")가 Argv에 배치됩니다.

마이크로소프트 "배치 언어"(.bat)도 이러한 아나키즘 환경에 예외는 아니며 토큰화 및 이스케이프를 위한 고유한 규칙을 개발했습니다.또한 cmd.exe의 명령 프롬프트는 새로 실행되는 프로세스로 인수를 전달하기 전에 명령줄 인수(대부분 변수 대체 및 이스케이프용)를 사전 처리하는 것처럼 보입니다.배치 언어 및 cmd 이스케이핑의 하위 수준 세부 정보에 대한 자세한 내용은 이 페이지의 job 및 dbenham의 우수한 답변에서 확인할 수 있습니다.


C에 간단한 명령줄 유틸리티를 구축하고 테스트 사례에 대해 설명하는 내용을 살펴보겠습니다.

int main(int argc, char* argv[]) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("argv[%d][%s]\n", i, argv[i]);
    }
    return 0;
}

(참고: argv[0]은(는) 항상 실행 파일의 이름이며, 간략하게 설명하기 위해 아래에서 생략합니다.Windows XP SP3에서 테스트되었습니다.Visual Studio 2005로 컴파일됨.)

> test.exe "a ""b"" c"
argv[1][a "b" c]

> test.exe """a b c"""
argv[1]["a b c"]

> test.exe "a"" b c
argv[1][a" b c]

제가 직접 테스트한 몇 가지는:

> test.exe a "b" c
argv[1][a]
argv[2][b]
argv[3][c]

> test.exe a "b c" "d e
argv[1][a]
argv[2][b c]
argv[3][d e]

> test.exe a \"b\" c
argv[1][a]
argv[2]["b"]
argv[3][c]

백분율 확장 규칙

다음은 젭의 답변에서 1단계에 대한 확장된 설명입니다(배치 모드와 명령줄 모드 모두에 유효).

1단계) 왼쪽부터 시작하여 각 문자를 스캔합니다.%또는<LF>발견된 경우

  • 1.05 (줄 바꿈)<LF>)
  • 캐릭터가<LF>그리고나서
    • 라인의 나머지 부분을 에서 삭제(무시)합니다.<LF>앞으로
    • 2.0 단계로 이동
  • 그렇지 않으면 문자가 다음과 같아야 합니다.%1.1로 진행합니다.
  • 1.1(표준)%) 명령줄 모드일 경우 건너뜁니다.
  • 배치 모드와 그 뒤에 다른 배치 모드가 있는 경우%그리고나서
    교체하다%%독신으로%스캔을 계속합니다.
  • 1.2 (임의 인수) 명령줄 모드일 경우 건너뜁니다.
  • 그렇지 않으면 배치 모드일 경우
    • 다음에 오는 경우*그러면 명령 확장이 활성화됩니다.
      교체하다%*모든 명령줄 인수의 텍스트(인수가 없으면 없음으로 대체)를 사용하여 검색을 계속합니다.
    • 그렇지 않은 경우 다음과 같습니다.<digit>그리고나서
      교체하다%<digit>인수 값을 사용하여(정의되지 않은 경우 아무것도 없음으로 대체) 검색을 계속합니다.
    • 그렇지 않은 경우 다음과 같습니다.~그러면 명령 확장이 활성화됩니다.
      • 유효한 인수 수정자 목록(선택 사항)이 뒤에 오는 경우 필요한 경우<digit>그리고나서
        교체하다%~[modifiers]<digit>수정된 인수 값을 사용하여(정의되지 않았거나 지정된 $PATH: 수식자가 정의되지 않은 경우 없음으로 대체) 검색을 계속합니다.
        참고: 한정자는 대소문자를 구분하지 않으며, $PATH: 한정자는 한 번만 나타날 수 있고 다음에 오는 마지막 한정자여야 하는 경우를 제외하고는 모든 순서에서 여러 번 나타날 수 있습니다.<digit>
      • 그렇지 않으면 잘못된 수정된 인수 구문으로 인해 치명적인 오류가 발생합니다. 배치 모드일 경우 구문 분석된 모든 명령이 중단되고 배치 처리가 중단됩니다!
  • 1.3 (변수)
  • 그렇지 않으면 명령 확장이 비활성화된 경우
    이전에 끊어진 다음 문자열을 봅니다.%또는 버퍼 끝을 VAR이라고 합니다(빈 목록일 수 있음).
    • 다음 문자가 다음인 경우:%그리고나서
      • VAR이 정의된 경우
        교체하다%VAR%VAR 값을 사용하여 스캔을 계속합니다.
      • 그렇지 않으면 배치 모드일 경우
        제거한다.%VAR%스캔을 계속합니다.
      • 그렇지 않으면 1.4로 이동합니다.
    • 그렇지 않으면 1.4로 이동합니다.
  • 그렇지 않으면 명령 확장이 활성화된 경우
    이전에 끊어진 다음 문자열을 봅니다.% :또는 버퍼 끝을 VAR이라고 합니다(빈 목록일 수 있음).VAR이 이전에 중단된 경우:그리고 그 다음 캐릭터는.%그런 다음 포함:VAR의 마지막 문자로, 그리고 그 전에 끊어집니다.%.
    • 다음 문자가 다음인 경우:%그리고나서
      • VAR이 정의된 경우
        교체하다%VAR%VAR 값을 사용하여 스캔을 계속합니다.
      • 그렇지 않으면 배치 모드일 경우
        제거한다.%VAR%스캔을 계속합니다.
      • 그렇지 않으면 1.4로 이동합니다.
    • 그렇지 않으면 다음 캐릭터가:그리고나서
      • VAR이 정의되지 않은 경우
        • 배치 모드인 경우
          제거한다.%VAR:스캔을 계속합니다.
        • 그렇지 않으면 1.4로 이동합니다.
      • 그렇지 않으면 다음 캐릭터가~그리고나서
        • 다음 문자열이 다음 패턴과 일치하는 경우[integer][,[integer]]%그리고나서
          교체하다%VAR:~[integer][,[integer]]%값의 하위 문자열을 사용하여(빈 문자열이 발생할 수 있음) 스캔을 계속합니다.
        • 그렇지 않으면 1.4로 이동합니다.
      • 그렇지 않은 경우 다음과 같습니다.=또는*=그리고나서
        잘못된 변수 검색 및 바꾸기 구문으로 인해 치명적인 오류가 발생합니다. 배치 모드일 경우 구문 분석된 모든 명령이 중단되고 배치 처리가 중단됩니다!
      • 그렇지 않은 경우 다음 문자열이 다음 패턴과 일치합니다.[*]search=[replace]%여기서 검색은 다음을 제외한 모든 문자 집합을 포함할 수 있습니다.=및 바꾸기는 다음을 제외한 모든 문자 집합을 포함할 수 있습니다.%,그리고나서
        교체하다%VAR:[*]search=[replace]%검색 및 교체(빈 문자열이 발생할 수 있음)를 수행한 후 VAR 값을 사용하여 검색을 계속합니다.
      • 그렇지 않으면 1.4로 이동합니다.
  • 1.4(%)
    • 그렇지 않은 경우 배치 모드
      제거한다.%다음 문자부터 스캔을 계속합니다.%
    • 그렇지 않으면 선두를 유지합니다.%그리고 저장된 선행 문자 다음 문자부터 스캔을 계속합니다.%

위의 내용은 이 배치를 사용하는 이유를 설명하는 데 도움이 됩니다.

@echo off
setlocal enableDelayedExpansion
set "1var=varA"
set "~f1var=varB"
call :test "arg1"
exit /b  
::
:test "arg1"
echo %%1var%% = %1var%
echo ^^^!1var^^^! = !1var!
echo --------
echo %%~f1var%% = %~f1var%
echo ^^^!~f1var^^^! = !~f1var!
exit /b

다음과 같은 결과를 제공합니다.

%1var% = "arg1"var
!1var! = varA
--------
%~f1var% = P:\arg1var
!~f1var! = varB

참고 1 - 1단계는 REM 문을 인식하기 전에 발생합니다.이는 비고가 잘못된 인수 확장 구문을 가지고 있거나 잘못된 변수 검색 및 구문을 대체할 경우 치명적인 오류를 생성할 수 있다는 것을 의미하기 때문에 매우 중요합니다!

@echo off
rem %~x This generates a fatal argument expansion error
echo this line is never reached

참고 2 - % 구문 분석 규칙의 또 다른 흥미로운 결과:이름에 :을 포함하는 변수를 정의할 수 있지만 명령 확장을 사용하지 않도록 설정하지 않으면 확장할 수 없습니다.한 가지 예외가 있습니다. 명령 확장을 사용하는 동안 끝에 단일 콜론을 포함하는 변수 이름을 확장할 수 있습니다.그러나 변수 이름이 콜론으로 끝나는 경우에는 하위 문자열을 수행하거나 검색 및 바꾸기 작업을 수행할 수 없습니다.아래의 배치 파일(jeb의 호의)은 이 동작을 보여줍니다.

@echo off
setlocal
set var=content
set var:=Special
set var::=double colon
set var:~0,2=tricky
set var::~0,2=unfortunate
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%
echo Now with DisableExtensions
setlocal DisableExtensions
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%

참고 3 - 그의 게시물에 제시된 구문 분석 규칙 순서의 흥미로운 결과:찾기 및 지연 확장으로 바꾸기를 수행할 때 찾기 및 바꾸기 용어의 특수 문자는 이스케이프하거나 따옴표로 묶어야 합니다.그러나 백분율 확장의 경우 상황이 다릅니다. 즉, 검색 용어를 피해서는 안 됩니다(따옴표로 묶을 수 있음).대체 문자열의 백분율은 의도에 따라 이스케이프 또는 따옴표가 필요하거나 필요하지 않을 수 있습니다.

@echo off
setlocal enableDelayedExpansion
set "var=this & that"
echo %var:&=and%
echo "%var:&=and%"
echo !var:^&=and!
echo "!var:&=and!"

지연된 확장 규칙

다음은 젭의 답변에서 5단계에 대한 확장되고 더 정확한 설명입니다(배치 모드와 명령줄 모드 모두에 유효).

5단계) 확장 지연

다음 조건 중 하나가 적용되는 경우 이 단계를 건너뜁니다.

  • 지연 확장이 비활성화되었습니다.
  • 명령은 파이프 양쪽의 괄호 안에 있습니다.
  • 들어오는 명령 토큰은 "벌거벗은" 배치 스크립트이며, 이는 다음과 연결되지 않음을 의미합니다.CALL괄호로 묶은 블록, 모든 형태의 명령 연결(&,&&또는||) 또는 파이프|.

지연된 확장 프로세스는 토큰에 독립적으로 적용됩니다.명령에는 여러 개의 토큰이 있을 수 있습니다.

  • 명령 토큰입니다.대부분의 명령에서 명령 이름 자체는 토큰입니다.그러나 일부 명령에는 5단계의 토큰으로 간주되는 특수 영역이 있습니다.
    • for ... in(TOKEN) do
    • if defined TOKEN
    • if exists TOKEN
    • if errorlevel TOKEN
    • if cmdextversion TOKEN
    • if TOKEN comparison TOKEN비교가 되는 곳에==,equ,neq,lss,leq,gtr또는geq
  • 인수 토큰
  • 리디렉션 대상 토큰(리다이렉션당 하나씩)

포함되지 않은 토큰은 변경되지 않습니다.!.

적어도 하나를 포함하는 각 토큰에 대해!왼쪽에서 오른쪽으로 각 문자 검색^또는!그리고 발견되면,

  • 5.1 (카트 탈출) 필요한 작업!또는^리터럴
  • 문자가 캐럿인 경우^그리고나서
    • 제거합니다.^
    • 다음 문자를 스캔하여 리터럴로 보존
    • 검색 계속
  • 5.2 (변수)
  • 문자가 다음인 경우!,그리고나서
    • 명령 확장이 비활성화된 경우
      이전에 끊어진 다음 문자열을 봅니다.!또는<LF>VAR이라고 부릅니다(빈 목록일 수 있음).
      • 다음 문자가 다음인 경우:!그리고나서
        • VAR이 정의된 경우,
          교체하다!VAR!VAR 값을 사용하여 스캔을 계속합니다.
        • 그렇지 않으면 배치 모드일 경우
          제거한다.!VAR!스캔을 계속합니다.
        • 그렇지 않으면 5.2.1로 이동합니다.
      • 그렇지 않으면 5.2.1로 이동합니다.
    • 그렇지 않으면 명령 확장이 활성화된 경우
      이전에 끊어진 다음 문자열을 봅니다.!,:또는<LF>VAR이라고 부릅니다(빈 목록일 수 있음).VAR이 이전에 중단된 경우:그리고 그 다음 캐릭터는.!그런 다음 포함:VAR의 마지막 문자로, 그리고 그 전에 끊어집니다.!
      • 다음 문자가 다음인 경우:!그리고나서
        • VAR이 존재하는 경우,
          교체하다!VAR!VAR 값을 사용하여 스캔을 계속합니다.
        • 그렇지 않으면 배치 모드일 경우
          제거한다.!VAR!스캔을 계속합니다.
        • 그렇지 않으면 5.2.1로 이동합니다.
      • 그렇지 않으면 다음 캐릭터가:그리고나서
        • VAR이 정의되지 않은 경우
          • 배치 모드인 경우
            제거한다.!VAR:스캔을 계속합니다.
          • 그렇지 않으면 5.2.1로 이동합니다.
        • 그렇지 않으면 다음 캐릭터가~그리고나서
          • 다음 문자열이 다음 패턴과 일치하는 경우[integer][,[integer]]!그런 다음 바꾸기!VAR:~[integer][,[integer]]!값의 하위 문자열을 사용하여(빈 문자열이 발생할 수 있음) 스캔을 계속합니다.
          • 그렇지 않으면 5.2.1로 이동합니다.
        • 그렇지 않은 경우 다음 문자열이 다음 패턴과 일치합니다.[*]search=[replace]!여기서 검색은 다음을 제외한 모든 문자 집합을 포함할 수 있습니다.=및 바꾸기는 다음을 제외한 모든 문자 집합을 포함할 수 있습니다.!,그리고나서
          교체하다!VAR:[*]search=[replace]!검색 및 교체(빈 문자열이 발생할 수 있음)를 수행한 후 VAR 값을 사용하여 검색을 계속합니다.
        • 그렇지 않으면 5.2.1로 이동합니다.
      • 그렇지 않으면 5.2.1로 이동합니다.
    • 5.2.1
      • 배치 모드인 경우 선행 모드를 제거합니다.!
        그렇지 않으면 선두를 유지합니다.!
      • 저장된 선행 문자 뒤에 다음 문자부터 검색을 시작하여 검색을 계속합니다.!

지적된 바와 같이, 명령어는 μSoftland에서 전체 인수 문자열을 전달하며, 이를 자체적으로 사용하기 위해 별도의 인수로 구문 분석하는 것은 명령어에 달려 있습니다.서로 다른 프로그램 간에는 일관성이 없기 때문에 이 프로세스를 설명하는 규칙 집합이 하나도 없습니다.당신은 당신의 프로그램이 사용하는 C 라이브러리가 무엇인지 각 코너 케이스를 확인해야 합니다.

시스템에 관한 한.bat파일 이동, 다음은 테스트입니다.

c> type args.cmd
@echo off
echo cmdcmdline:[%cmdcmdline%]
echo 0:[%0]
echo *:[%*]
set allargs=%*
if not defined allargs goto :eof
setlocal
@rem Wot about a nice for loop?
@rem Then we are in the land of delayedexpansion, !n!, call, etc.
@rem Plays havoc with args like %t%, a"b etc. ugh!
set n=1
:loop
    echo %n%:[%1]
    set /a n+=1
    shift
    set param=%1
    if defined param goto :loop
endlocal

이제 몇 가지 테스트를 실행할 수 있습니다.μSoft가 무엇을 하려고 하는지 파악할 수 있는지 확인해 보십시오.

C>args a b c
cmdcmdline:[cmd.exe ]
0:[args]
*:[a b c]
1:[a]
2:[b]
3:[c]

아직까지는 괜찮습니다. (재미없는 것은 빼겠습니다.)%cmdcmdline%그리고.%0이제부터.)

C>args *.*
*:[*.*]
1:[*.*]

파일 이름 확장명이 없습니다.

C>args "a b" c
*:["a b" c]
1:["a b"]
2:[c]

따옴표를 사용하면 인수 분할을 방지할 수 있지만 따옴표를 제거할 수 없습니다.

c>args ""a b" c
*:[""a b" c]
1:[""a]
2:[b" c]

연속적인 큰따옴표는 그들이 가지고 있었을 수도 있는 특별한 구문 분석 기능을 잃게 합니다.@Beniot의 예:

C>args "a """ b "" c"""
*:["a """ b "" c"""]
1:["a """]
2:[b]
3:[""]
4:[c"""]

퀴즈: 환경 변수의 값을 단일 인수로 전달하는 방법(즉,%1배트 파일로?

c>set t=a "b c
c>set t
t=a "b c
c>args %t%
1:[a]
2:["b c]
c>args "%t%"
1:["a "b]
2:[c"]
c>Aaaaaargh!

제정신인 파싱은 영원히 망가진 것처럼 보입니다.

다양한 기능을 추가해 보십시오.^,\,',&(&c.) 이 예제의 문자.

위에 이미 훌륭한 답변이 몇 가지 있습니다. 하지만 질문의 한 부분에 답하자면,

set a =b, echo %a %b% c% → bb c%

= 앞에 공백이 있기 때문에 다음과 같은 변수가 생성됩니다.%a<space>%그래서 당신이echo %a %정확하게 평가되는 것은b.

나머지 부분b% c%그런 다음 일반 텍스트 + 정의되지 않은 변수로 평가됩니다.% c%나를 위해, 그것은 타이핑된 대로 울려 퍼져야 합니다.echo %a %b% c%돌아온다bb% c%

변수 이름에 공백을 포함하는 기능은 계획된 '기능'이라기보다는 무시에 가깝다고 생각합니다.

FOR-루프 메타 변수 확장

이것은 승인된 답변의 4단계에 대한 확장 설명입니다(배치 파일 모드와 명령줄 모드 모두에 적용 가능).물론.for명령이 활성 상태여야 합니다.다음은 명령행 부분의 다음 처리에 대해 설명합니다.do배치 파일 모드에서는%%이미 로 변환되었습니다.%앞서 말한 바와 같이.%- 팽창 단계(1단계).

  • 을 찾아다니다.%- 기호(왼쪽에서 시작하여 줄의 끝까지). 하나가 발견되면 다음을 수행합니다.
    • 명령 확장이 활성화된 경우(기본값), 다음 문자가~예인 경우, 다음을 수행합니다.
      • 대소문자를 구분하지 않는 집합에서 다음 문자를 최대한 많이 사용합니다.fdpnxsatz(각각 여러 번이라도) 다음을 정의하는 문자 앞에 있는 것.for변수 참조 또는$-사인; 만약 그렇다면.$-sign이 발생한 경우:
        • 을 찾아 보다.:발견된 경우 다음을 1수행합니다.
          • 다음 문자가 있는 경우:그것을 …로 삼다for변수 참조 및 예상대로 확장(정의되지 않은 경우)한 다음 해당 문자 위치에서 확장 및 스캔을 계속하지 마십시오.
          • 만약에:마지막 문자입니다. 충돌합니다!
        • 기타(아니오):발견됨) 아무것도 확장하지 않음;
      • 그렇지 않은 경우(아니오인 경우)$-sign이 발생했습니다)를 확장합니다.for정의되지 않은 경우 모든 수식어를 사용하는 변수. 그런 다음 확장하지 않고 해당 문자 위치에서 스캔을 계속합니다.
    • 그렇지 않은 경우(아니오인 경우)~를 찾거나 명령 확장이 비활성화됨) 다음 문자를 확인합니다.
      • 더 이상 사용할 수 있는 문자가 없으면 아무것도 확장하지 마십시오.
      • 다음 등장인물이.%아무것도 확장하지 말고 이 문자2 위치에서 스캔 시작으로 돌아갑니다.
      • 그렇지 않으면 다음 문자를 a로 사용합니다.for변수 참조 및 확장(정의되지 않은 경우), 다음은 확장하지 않음.
  • 다음 문자 위치에서 스캔 시작으로 돌아갑니다(사용 가능한 문자가 있는 한).

사이의 문자열$그리고.:는 환경 변수의 이름으로 간주되며, 환경 변수의 이름은 비어 있을 수 없으므로 동작은 정의되지 않은 환경 변수의 이름과 동일합니다.
이는 다음을 의미합니다.for라는 이름의 메타데이터%없이 확장할 수 없습니다.~- 수식자.


원본 소스:%%~p 변수 다음에 문자열 리터럴을 안전하게 에코하는 방법

편집: 수락된 답변을 참조하십시오. 다음은 잘못된 것이며 TinyPerl에 명령줄을 전달하는 방법만 설명합니다.


견적과 관련하여, 저는 그 행동이 다음과 같다고 생각합니다.

  • …일 때에"발견됨, 문자열 글로빙이 시작
  • 문자열 글로빙이 발생하는 경우:
    • 아닌 모든 등장인물"지구본
    • …일 때에"검색됨:
      • 그 뒤에 오는 경우에는""(3루타 기록)"그런 다음 이중 따옴표가 문자열에 추가됩니다.
      • 그 뒤에 오는 경우에는"(2루타를 기록함)"그런 다음 문자열 및 문자열 글로빙 끝에 이중 따옴표가 추가됩니다.
      • 다음 캐릭터가 아닐 경우"스트링 글러브 끝
    • 줄이 끝나면 문자열 글로빙이 끝납니다.

간단히 말해서:

"a """ b "" c"""두 개의 문자열로 구성됩니다.a " b "그리고.c"

"a"","a"""그리고."a""""줄의 끝에 있는 경우 모두 동일한 문자열입니다.

Microsoft는 터미널의 소스 코드를 게시했습니다.구문 분석과 관련하여 명령줄과 유사하게 작동할 수 있습니다.아마도 누군가는 단말기의 구문 분석 규칙에 따라 역설계된 구문 분석 규칙을 테스트하는 데 관심이 있을 것입니다.

소스 코드에 대한 링크입니다.

언급URL : https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts

반응형