배치 환경에서 실행되는 다음과 같은 간단한 일련의 명령을 살펴보겠습니다.
>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단계에서 발견된 모든 리디렉션이 실행됩니다.
- 4단계와 5단계의 결과는 2단계에서 발견된 리디렉션에 영향을 미칠 수 있습니다.
- 리디렉션이 실패하면 명령의 나머지 부분이 중단됩니다.
||
실패한 리디렉션은 사용 되지 않는 한 ERRORLEVEL을 1로 설정하지 않습니다..
- 당신의명령줄사용하여
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]!
- 당신의박쥐/cmd선언하지 않고 파일
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]!"
@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
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]%
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]!
추가 내용:
[√]세트 /?
[√]명령 /?
[√]For 루프
[√]/F 루프의 경우
답변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
코드 시작 부분에 추가해야 하기 때문에 코드가 작동하지 않습니다 .
도움이 되었기를 바랍니다