배치 스크립트에서 지연된 확장은 어떻게 작동합니까?

배치 스크립트에서 지연된 확장은 어떻게 작동합니까?

배치 환경에서 실행되는 다음과 같은 간단한 일련의 명령을 살펴보겠습니다.

>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!

다음을 출력합니다.

>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!

따라서 분명히 그 가치로 확장되지 않습니다. 어떻게 해야 합니까?

답변1

출처:
5단계~에Windows 명령 해석기(CMD.EXE)는 스크립트를 어떻게 구문 분석합니까?

지연된 확장:지연된 확장이 켜져 있는 경우에만 명령이파이프 양쪽에 있는 괄호 안에 있는 블록이며 명령은"네이키드" 배치 스크립트(괄호가 없는 스크립트 이름, CALL, 명령 연결 또는 파이프).

  • 명령의 각 토큰은 지연된 확장을 위해 독립적으로 구문 분석됩니다.
    • 대부분의 명령은 두 개 이상의 토큰, 즉 명령 토큰, 인수 토큰 및 각 리디렉션 대상 토큰을 구문 분석합니다.
    • FOR 명령은 IN 절 토큰만 구문 분석합니다.
    • IF 명령은 비교 연산자에 따라 비교 값(1개 또는 2개)만 구문 분석합니다.
  • 구문 분석된 각 토큰에 대해 먼저 !. 그렇지 않은 경우 토큰은 구문 분석되지 않습니다 ^. 이는 문자에 중요합니다. 토큰에 가 포함되어 있으면 !각 문자를 왼쪽에서 오른쪽으로 스캔합니다.
    • 캐럿( ^)인 경우 다음 문자는 특별한 의미가 없으며 캐럿 자체가 제거됩니다.
    • 느낌표인 경우 다음 느낌표를 검색하고(캐럿은 더 이상 관찰되지 않음) 변수 값으로 확장합니다.
      • 연속적인 열기는 !하나로 축소됩니다.!
      • 페어링되지 않은 나머지 항목은 모두 !제거됩니다.
    • 이 단계에서 변수를 확장하는 것은 특수 문자가 더 이상 감지되지 않기 때문에 "안전"합니다( <CR>또는 <LF>).
    • 더 완전한 설명을 보려면 dbenham의 후반부를 읽어보세요. 동일한 스레드 - 느낌표 단계

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

  • 명령이 cmd.exe 내부에 있거나 배치 파일이거나 괄호로 묶인 명령 블록인 경우 를 통해 새 cmd.exe 스레드에서 실행되므로 %comspec% /S /D /c" commandBlock"명령 블록이 단계를 다시 시작하지만 이번에는 명령줄 모드에서.
    • 괄호 안에 명령 블록이 있으면 <LF>앞뒤에 명령이 있는 모든 블록이 로 변환됩니다 <space>&. 다른 것들은 <LF>벗겨졌습니다.
  • 이것으로 파이프 명령 처리가 끝났습니다.
  • 보다https://stackoverflow.com/q/8192318/1012053파이프 구문 분석 및 처리에 대한 자세한 내용

5.5단계) 리디렉션 실행:이제 2단계에서 발견된 모든 리디렉션이 실행됩니다.



여기에 이미지 설명을 입력하세요

  • 다음을 사용할 수도 있습니다.Delayed Expansion~에 의해cmd.exe깃발이 달린[/v:on | /v], 에또는/파일.

여기에 이미지 설명을 입력하세요

  • 당신의사용하여cmd.exe /v:on /c
set ar[0]=orange
set ar[1]=apple
set ar[2]=banana
for %i in (0,1,2) do cmd.exe /v:on /C"echo !ar[%i]!

  • 당신의/선언하지 않고 파일setlocal enabledelayedexpansion, 당신은 또한 사용할 수 있습니다cmd.exe /v:on /c "command & command | command || command..."
@echo off 

set "ar[0]=orange" 
set "ar[1]=apple"
set "ar[2]=banana" 
for %%i in (0,1,2)do cmd /v /c "echo\ !ar[%%i]!"

  • 당신의/선언setlocal enabledelayedexpansion:
@echo off 

set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana" 

setlocal enabledelayedexpansion
for %%i in (0,1,2)do echo\ !ar[%%i]!

enndlocal


  • 이에 대한 일부 레이아웃 차이/암호:
@echo off 
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana" 
for %%i in (0,1,2)do %ComSpec% /v:on /c"echo !ar[%%i]!"
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off 
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana" 
setlocal enabledelayedexpansion && for %%i in (0,1,2)do echo\ !ar[%%i]!
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off 
set "ar[0]=orange" && set "ar[1]=apple" && set "ar[2]=banana" 
for %%i in (0,1,2)do <con: %ComSpec% /v:on /c"echo !ar[%%i]!"
call <con: rem./ && %__APPDIR__%timeout.exe /t -1 && endlocal
  • 당신은 또한 사용할 수 있습니다call~에/또는 명령줄에서 이 값을 업데이트합니다.
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana" 
for %i in (0,1,2)do for %i in (0,1,2)do <con: call echo %ar[%i]%


  • 당신의/파일 또는 명령줄에서 다음 명령은 모두 동일하며 교체를 관찰합니다.%i~와 함께%%i다음에서 사용하는 경우/파일
for %i in (0,1,2) do %ComSpec% /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v:on /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec% /v /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do %ComSpec%/v/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c"echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c"echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v/recho !ar[%i]!
for %i in (0,1,2) do %ComSpec%/v/cecho !ar[%i]!

for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!

for %i in (0,1,2) do cmd/v/recho !ar[%i]!
for %i in (0,1,2) do cmd/v/cecho !ar[%i]!

답변2

지연 확장은 특히 For 루프에서 변수 값을 두 번 이상 확장하는 데 주로 사용됩니다.

에서 인용https://ss64.com/nt/delayedexpansion.html

지연된 확장을 사용하면 배치 파일 내의 변수가 구문 분석 시간이 아닌 실행 시간에 확장됩니다. 이 옵션은 SETLOCAL EnableDelayedExpansion 명령을 사용하여 설정됩니다.

변수 확장은 변수(예: %windir%)를 해당 값 C:\WINDOWS로 바꾸는 것을 의미합니다.

기본적으로 확장은 각 줄이 실행되기 전에 한 번만 발생합니다. !지연! 확장은 라인이 실행될 때마다 수행되거나 FOR 루프 명령의 각 루프에 대해 수행됩니다. 먼저 다음 예를 살펴보겠습니다.

set i=0
for /l %%a in (0,1,10) do (
  set /a i=%i%+1
  echo %i%
)

여기서는 1부터 10까지의 숫자가 출력될 것으로 예상합니다. 그러나 매번 출력할 때마다 0만 출력됩니다. 왜냐하면 변수가 한 번 확장될 때마다 값이 변경되지 않기 때문입니다.

이번에는 지연된 확장을 시도해 보겠습니다.

setlocal enabledelayedexpansion 
set i=0
for /l %%a in (0,1,10) do (
  set /a i=!i!+1
  echo !i!
)

이번에는 값을 확장할 때마다 값이 변경되므로 예상한 출력을 얻게 됩니다.

setlocal enabledelayedexpansion코드 시작 부분에 추가해야 하기 때문에 코드가 작동하지 않습니다 .

도움이 되었기를 바랍니다

관련 정보