2013-06-21 31 views
11

Khi tôi cố gắng sử dụng SHIFT bên trong khối IF Tôi thấy một số kết quả không mong muốn. Sử dụng này:Thay đổi hàng loạt Windows không hoạt động nếu chặn

@echo off 

if "%1"=="/p" (
    echo %1 
    shift 
    echo "shifted" 
    echo %1 
) 

tôi nhận được như sau:

C:\>ex.bat /p HAI 
/p 
"shifted" 
/p 

Tuy nhiên, khi tôi sử dụng mã này:

@echo off 

echo %1 
shift 
echo "shifted" 
echo %1 

tôi có được điều này:

C:\>ex.bat /p HAI 
/p 
"shifted" 
HAI 

tôi cần đầu ra thứ hai, nhưng trong một khối logic để tôi có thể lặp lại ove r nó. Tôi đang cố gắng để thực hiện một cái gì đó tương tự như câu trả lời của Jon ở đây: Using parameters in batch files at DOS command line, nhưng tôi đang gặp một số rắc rối. Tại sao chuyện này đang xảy ra?

+0

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

Trả lời

10

Đó 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 
2

thực sự bạn chỉ có thể thực hiện thay đổi bên ngoài nếu chặn:

@echo off 
if "%1"=="/p" (
    echo "%1" 
    goto:perform_shift; 
:aftersift 
    echo "%1" 
) 
goto:end; 

:perform_shift 
shift 
echo "shifted" 
goto:aftersift; 


:end 
+1

Đó là "loại tác phẩm", nhưng nó rất tệ. Nó ngụ ý rằng bạn đang nhảy trong một khối được chặn, mà không hoạt động. Khoảnh khắc bạn sử dụng GOTO trong một khối, bạn giết khối đó; các dấu ngoặc đơn ở đó, nhưng chúng không phục vụ mục đích nào. Điều này không quan trọng trong trường hợp này, nhưng rất quan trọng nếu khối là một phần của vòng lặp FOR. Nếu bạn GOTO trong vòng lặp FOR, thì vòng lặp sẽ bị hủy. – dbenham

+0

xem [EDIT 2016-07-15 trong câu trả lời của tôi] (http://stackoverflow.com/a/17241649/1012053) để biết thêm thông tin về lý do tại sao câu trả lời này không phải là một ý tưởng hay, cũng như đề xuất cho tốt hơn cách để làm điều tương tự một cách hiệu quả. – dbenham

Các vấn đề liên quan