Đó là hành vi mong đợi bởi vì %1
được mở rộng khi dòng được phân tích cú pháp và toàn bộ cấu trúc IF được lồng dấu được phân tích cú pháp tất cả trong một lần truyền. Vì vậy, bạn không thể nhìn thấy kết quả của SHIFT cho đến khi một dòng mới được phân tích cú pháp, điều này sẽ không xảy ra cho đến sau khi bạn đã rời khỏi khối được chặn của bạn.
Vấn đề tương tự cũng xảy ra khi mở rộng biến môi trường sử dụng %var%
. Với các biến môi trường, bạn có thể giải quyết vấn đề bằng cách bật mở rộng trễ bằng cách sử dụng SETLOCAL EnableDelayedExpansion
và sau đó sử dụng !var!
. Nhưng không có cách nào có thể so sánh để mở rộng các tham số bằng cách sử dụng mở rộng trễ.
EDIT 2013-06-21 - Không có cách nào so sánh được, nhưng có một cách đơn giản tương đối chậm.
Bạn có thể buộc đường bị lặp lại bằng cách sử dụng GỌI và tăng gấp đôi số %
.
@echo off
if "%1"=="/p" (
echo %1
shift
echo "shifted"
call echo %%1
)
EDIT 2016/07/15 Các code in Vladislav's answer là một thói quen xấu, vì nó ngụ ý rằng bạn có thể nhảy trở lại trong một khối mã sau khi bạn sử dụng GOTO rời khỏi nó. Điều đó chỉ đơn giản là không hoạt động. GOTO ngay lập tức giết bất kỳ khối mã được phân tích cú pháp nào. Bạn cũng có thể đã viết code Vladislav như:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
)
Nếu điều kiện là FALSE, sau đó toàn bộ khối được bỏ qua. Nếu điều kiện là TRUE, thì GOTO ngay lập tức giết chết khối, và sau đó thực hiện chọn bình thường tại nhãn: true (không có bối cảnh khối). Thêm )
ở cuối đơn giản là bị bỏ qua.
Lưu ý rằng bạn không thể thêm ELSE với cấu trúc này. Sau đây không cung cấp kết quả mong muốn:
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
) else (
echo This will execute regardless whether arg1 is /p or not
)
Nếu FALSE, thì chỉ khối ELSE được thực thi. nếu TRUE, thì khối trên cùng được thực hiện và ngay lập tức bị giết. Phần còn lại của mã được thực thi và dòng ) else (
bị bỏ qua vì hàm làm REM nếu trình phân tích cú pháp mong đợi một lệnh và không có dấu ngoặc đơn đang hoạt động nào chặn trên ngăn xếp.
Tôi đặc biệt khuyên bạn không bao giờ GOTO nhãn trong một khối mã được chặn theo cách tôi đã trình bày ở trên (hoặc như Vladislav đã làm).
Dưới đây là một cách tốt hơn (đơn giản hơn và không gây hiểu nhầm) để làm điều tương tự:
@echo off
if not "%1"=="/p" goto :skip
echo "%1"
shift
echo shifted
echo "%1"
:skip
Bạn có thể hỗ trợ một/THEN/khái niệm else if với một số nhãn phụ và gotos
@echo off
if not "%1"=="/p" goto :notP
echo "%1"
shift
echo shifted
echo "%1"
goto :endIf
:notP
echo not /p
:endIf
Tôi đã tìm thấy câu trả lời ở đây: [Shift không hoạt động trong tập lệnh batch] (http://social.technet.microsoft.com/Forums/scriptcenter/en-US/7bbbe8df-e3c0-46ab-aede-396c2b6f6184/shift-doesnt-work-in-batch-script) – piebie