2008-11-20 36 views
17

Tôi đang viết một tệp .bat đơn giản và tôi đã chạy vào một số hành vi kỳ lạ. Có một vài nơi mà tôi phải làm một cách đơn giản nếu có, nhưng mã bên trong các khối dường như không hoạt động chính xác.Vấn đề phạm vi kỳ lạ trong .bat tập tin

Dưới đây là một trường hợp đơn giản thể hiện được lỗi:

@echo off 

set MODE=FOOBAR 

if "%~1"=="" (
    set MODE=all 
    echo mode: %MODE% 
) else (
    set MODE=%~1 
    echo mode: %MODE% 
) 
echo mode: %MODE% 

Kết quả tôi nhận được là:

C:\>test.bat test 
mode: FOOBAR 
mode: test 

Tại sao tiếng vang bên trong khối mã không nhận được giá trị mới của các biến? Trong mã thực tế tôi viết, tôi cần phải xây dựng một vài biến và tham khảo chúng trong phạm vi của if/else. Tôi có thể chuyển đổi này để sử dụng nhãn và gotos thay vì một if/else, nhưng điều đó không có vẻ gần như sạch sẽ.

Điều gì gây ra hành vi này? Có loại giới hạn nào về các biến trong các khối mã không?

Trả lời

26

Bạn đang chạy vào vấn đề mở rộng biến tĩnh của cmd. Biến MODE chỉ được đánh giá một lần. Bạn có thể thấy điều này nếu bạn bỏ qua @echo off line.

Từ bộ /? tài liệu:

Finally, support for delayed environment variable expansion has been added. This support is always disabled by default, but may be enabled/disabled via the /V command line switch to CMD.EXE. See CMD /?

Delayed environment variable expansion is useful for getting around the limitations of the current expansion which happens when a line of text is read, not when it is executed. The following example demonstrates the problem with immediate variable expansion:

set VAR=before 
if "%VAR%" == "before" (
    set VAR=after 
    if "%VAR%" == "after" @echo If you see this, it worked 
) 

would never display the message, since the %VAR% in BOTH IF statements is substituted when the first IF statement is read, since it logically includes the body of the IF, which is a compound statement. So the IF inside the compound statement is really comparing "before" with "after" which will never be equal. Similarly, the following example will not work as expected:

set LIST= 
for %i in (*) do set LIST=%LIST% %i 
echo %LIST% 

in that it will NOT build up a list of files in the current directory, but instead will just set the LIST variable to the last file found. Again, this is because the %LIST% is expanded just once when the FOR statement is read, and at that time the LIST variable is empty. So the actual FOR loop we are executing is:

for %i in (*) do set LIST= %i 

which just keeps setting LIST to the last file found.

Delayed environment variable expansion allows you to use a different character (the exclamation mark) to expand environment variables at execution time. If delayed variable expansion is enabled, the above examples could be written as follows to work as intended:

set VAR=before 
if "%VAR%" == "before" (
    set VAR=after 
    if "!VAR!" == "after" @echo If you see this, it worked 
) 

set LIST= 
for %i in (*) do set LIST=!LIST! %i 
echo %LIST% 
+0

Có cách nào để thiết lập cờ mà programatically ở phía trên cùng của một file bat? Hầu hết thời gian này sẽ được chạy bởi một tập tin bat khác, và môi trường mà nó chạy không cố định (có thể được nhấn đúp, có thể được chạy từ một trình bao Cygwin, có thể là từ cmd, vv). – Herms

+3

@Herms, "setlocal enabledelayedexpansion" khi bắt đầu, "endlocal" ở cuối. – paxdiablo

+0

Cảm ơn. Điều này đã lưu paxdiablo mông của tôi. –

-2

Dường như đọc và viết sử dụng các quy tắc phạm vi khác nhau.

Nếu bạn loại bỏ dòng này

set MODE=FOOBAR 

nó sẽ làm việc như mong đợi. Vì vậy, bạn có thể sẽ cần phải có một loạt phức tạp nếu nếu/elses để có được các biến dân cư như bạn muốn.

+0

Thực tế là không, không. Điều đó đặt ở đầu không phải là ban đầu ở đó. Nếu tôi bỏ qua điều đó thì lần đầu tiên tôi chạy tập tin dơi, tiếng vọng đầu tiên trống. Lần thứ hai tôi chạy nó (từ cùng một ví dụ cmd) echo đầu tiên cho thấy giá trị được sử dụng cuối cùng. – Herms

+0

Bạn nói đúng, tôi sẽ chạy kịch bản lần thứ hai .. phát hiện tốt! –

+0

Xóa câu trả lời của bạn? –

2

setlocal EnableDelayedExpansion

sẽ cho phép/v cờ

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