Khi bạn thực thi tệp lô, mỗi dòng hoặc khối dòng (các dòng được bao quanh trong dấu ngoặc đơn) được phân tích cú pháp đầu tiên và sau đó được thực hiện. Trong quá trình phân tích cú pháp, các hoạt động đọc trên các biến được thay thế bằng giá trị bên trong biến trước khi các lệnh được thực thi. Vì vậy, nếu trong một dòng/khối một giá trị biến được thay đổi, bạn không thể lấy giá trị thay đổi này khi trình phân tích cú pháp đã loại bỏ hoạt động đọc với giá trị trong biến trước khi thay đổi được thực hiện.
Vì vậy, mã của bạn
set p=notepad.exe&%p%
được phân tách và chuyển đổi sang
set p=notepad.exe&
nơi hoạt động đọc để có được %p%
đã được thay thế bằng giá trị trong biến (mẫu giả định biến là trống). Sau đó, dòng phân tích cú pháp này được thực hiện.
Tại sao lại hoạt động lần thứ hai? Bởi vì trong lần chạy trước, biến đã được đặt và, nếu nó chưa được đặt lại, khi trình phân tích cú pháp thực hiện thay thế trong lần chạy thứ hai biến chứa giá trị để thay thế trong dòng.
Để thấy rằng đây là một phân tích trước khi thực hiện hành vi, bạn có thể thay đổi dòng của bạn để
set p=notepad.exe&set p
nghĩa là, thiết lập biến và đổ nội dung môi trường (biến bắt đầu với p) và bạn sẽ thấy rằng biến đã được đặt thành notepad.exe
. Vì dòng này không chứa bất kỳ thao tác đọc nào trên biến, mọi thứ hoạt động như mong đợi.
Cách giải quyết sự cố của bạn?Có một số tùy chọn
Chậm mở rộng
Khi mở rộng chậm được kích hoạt, cú pháp trên biến nội dung đã có thể được thay đổi, khi cần thiết, %var%
-!var!
, chỉ để phân tích cú pháp mà thay vào hoạt động đọc cần phải được trì hoãn cho đến khi thực hiện lệnh
setlocal enabledelayedexpansion
set p=notepad.exe&!p!
hành vi này tương tự có thể được kích hoạt nếu bộ xử lý lệnh được gọi với /v:on
cmd /v:on /c "set p=notepad.exe&!p!"
quân một phân tích cú pháp thứ hai trên lệnh
này sử dụng lệnh call
để buộc một phân tích cú pháp thứ hai trên dòng
set p=notepad.exe&call %%p%%
Các phân tích cú pháp mặc định đầu tiên thay thế các literal %%p%%
với nghĩa đen %p%
(%%
là dấu phần trăm thoát) mà không thực hiện bất kỳ thay thế biến nào và khi lệnh call
được thực thi, dòng được phân tích cú pháp một lần nữa, vì vậy, chữ số %p%
được hiểu là biến đọc và được thay thế bằng giá trị trong biến
Điều gì sẽ sử dụng? Nó phụ thuộc. Giải pháp mở rộng bị trì hoãn có thời gian thực hiện tốt hơn mà giải pháp call
(call
lệnh hoạt động nhiều hơn), nhưng khi mở rộng trễ được bật ký tự dấu chấm than (!
) chứa trong dữ liệu trở thành vấn đề cần được xử lý đúng cách.
Nếu mục đích của bạn là mở một số ví dụ như notepad hoặc một số tập tin, bạn có thể làm điều đó trực tiếp trong một dòng, chính xác những gì bạn muốn với biến này? – ZAT
@ZAT Nó chỉ là một ví dụ. Mục đích của tôi là chuyển đổi một tập tin batch phức tạp thành một dòng duy nhất. Tất cả các mã được chuyển đổi ngoại trừ thiết lập một biến, như trên. Tôi không muốn thực thi tập tin batch trực tiếp. –
Nếu bạn đang lưu trữ mã phức tạp trong các biến, thì bạn có thể quan tâm đến các macro [Hàng loạt "có đối số] (http://www.dostips.com/forum/viewtopic.php?f=3&t=1827) – dbenham