2013-05-13 17 views
6

Tôi có một which.bat trên Windows 7,

@echo off 
REM This bat searches a file in PATH list to see whether a file can be found. 
REM If found, it shows the file's full path. 
REM  which.bat gcc.exe 
REM shows 
REM  gcc.exe is found: D:\GMU\MinGW2\bin\gcc.exe 
REM 
REM Note: Filename extension is significant in the search. E.g. If you run 
REM  which.bat gcc 
REM gcc.exe will not be matched. 

IF "%1" == "" goto END 

IF "%~$PATH:1" == "" (
     echo %1 is not found in any directories from PATH env-var. 
    ) ELSE (
     echo %1 is found: %~$PATH:1 
    ) 

:END 

dơi này hoạt động tốt cho đến khi tôi tìm thấy một hành vi kỳ lạ ngày hôm nay.

Có một tập tin O:\temp\pfiles (x86)\mystuff.txt, và PATH có nội dung:

PATH=O:\temp\pfiles (x86);D:\CmdUtils 

Chạy which mystuff.txt, tôi có rất lạ đầu ra:

\mystuff.txt was unexpected at this time. 

enter image description here

Sau khi một số poking xung quanh , Tôi thấy rằng (x86) trong tên thư mục gây ra thứ e vấn đề. Để khắc phục, tôi phải thêm dấu ngoặc kép để các echo, như thế này:

echo %1 is found: "%~$PATH:1" 

Nhược điểm của tinh chỉnh như vậy là rõ ràng: Các dấu ngoặc kép được in vào màn hình mà không phải luôn luôn mong muốn trong quan điểm của lập trình viên.

Có ai có thể giúp giải thích hành vi kỳ lạ này không?

Tôi thấy vấn đề này bởi vì trong env thực sự của mình, tôi có một số đường dẫn như C:\Program Files (x86)\Common Files\NetSarang trong PATH, hiển thị chính xác cùng một triệu chứng.

enter image description here

+0

Cảm ơn bạn đã cho tôi biết. '' where.exe'' là rất tốt. Tôi đã sử dụng which.bat từ Windows XP, nơi chưa có 'where.exe''. –

+0

thông tin tốt ... nhưng nếu bạn đang tìm kiếm một 'thực thi' và không cung cấp phần mở rộng thì không hoạt động ... sử dụng 'where.exe' rồi ... hoặc 'which' nếu ou nằm trong linux ... hoặc chỉ cần cài đặt Cygwin và sử dụng 'which' ... hoạt động tuyệt vời !!! – ZEE

Trả lời

8

MS Dos là thực hiện vỏ khá đơn giản, và như tôi đã tìm ra rằng giải thích của một dòng lệnh DOS đi trong 2 giai đoạn:

  1. đánh giá của các biến trong dòng hiện
  2. diễn giải dòng lệnh được đánh giá

Trong trường hợp này dòng lệnh của bạn:

IF "%~$PATH:1" == "" (
     echo %1 is not found in any directories from PATH env-var. 
    ) ELSE (
     echo %1 is found: %~$PATH:1 
    ) 

sẽ được hiểu là:

IF "O:\temp\pfiles (x86)\mystuff.txt" == "" (
     echo mystuff is not found in any directories from PATH env-var. 
    ) ELSE (
     echo mystuff.txt is found: O:\temp\pfiles (x86)\mystuff.txt 
    ) 

Bây giờ chúng ta có thể nhận thấy những vấn đề trong (x86), tức là thông dịch viên xem đây bằng cách nào đó như thế này - lần đầu tiên ) đóng else statement:

) ELSE (
     echo mystuff.txt is found: O:\temp\pfiles (x86 
)\mystuff.txt 
) 

Giải pháp: đặt "" xung quanh tất cả các biến có khả năng có vấn đề.

Tôi thường đặt dấu ngoặc kép quanh toàn bộ nội dung lệnh echo, ví dụ:

echo "%1 is found: %~$PATH:1" 
+0

Thực sự giải thích cụ thể. –

2

tôi có thể đoán tại một lời giải thích (mặc dù không phải là một hữu ích): phân tích cú pháp cmd.exe không phải là rất thông minh - nó bị nhầm lẫn bởi các parens trong %~$PATH:1 - khi nó mở rộng biến và nhìn thấy các ký tự ), nó giả định rằng đó là paren closig cho dòng .(Tôi nghĩ rằng nó không làm bất cứ điều gì với các ký tự ( trong việc mở rộng bởi vì những người chỉ có ý nghĩa ở đầu của một lệnh).

Bạn có thể giải quyết vấn đề bằng cách đảm bảo rằng mở rộng có thể chứa ')' không nằm trong nhóm lệnh (...) hoặc được trích dẫn (như bạn đã tìm thấy). Vì bạn không muốn báo giá, các giải pháp khác có thể trông giống như:

@echo off 
REM This bat searches a file in PATH list to see whether a file can be found. 
REM If found, it shows the file's full path. 
REM  which.bat gcc.exe 
REM shows 
REM  gcc.exe is found: D:\GMU\MinGW2\bin\gcc.exe 
REM 
REM Note: Filename extension is significant in the search. E.g. If you run 
REM  which.bat gcc 
REM gcc.exe will not be matched. 

IF "%1" == "" goto END 

IF "%~$PATH:1" == "" (
     echo %1 is not found in any directories from PATH env-var. 
    ) ELSE (
     call :printfound %1 
    ) 

goto END 

:printfound 
echo %1 is found: %~$PATH:1 
goto :eof 

:END 

Thật xấu xí, nhưng đó là điều bạn phải làm với kịch bản cmd.exe.

4

Hiện tại vấn đề đã rõ ràng (từ Michael Burr và Robert Lujo), tôi cố gắng trình bày một giải pháp.

Bạn cần báo giá, nhưng bạn không muốn hiển thị chúng.

Với việc mở rộng chậm ngoặc đóng cửa là vô hại

setlocal EnableDelayedExpansion 
IF "%~$PATH:1" == "" (
     echo %1 is not found in any directories from PATH env-var. 
    ) ELSE (
     set "found=%~$PATH:1"  
     echo %1 is found: !found! 
    ) 

Hoặc chỉ với một báo biến mất

IF "%~$PATH:1" == "" (
     echo %1 is not found in any directories from PATH env-var. 
    ) ELSE (
     for %%^" in ("") do (
     echo %1 is found: %%~"%~$PATH:1 
    ) 
    ) 
+0

Phương thức EnableDelayedExpansion ít gây nhầm lẫn. Cảm ơn bạn. –

+1

Wow, '' set "found = 1" '' giống hệt với '' set found = 1'', ​​mẹo rất hay. –