2013-05-13 12 views
6

Mam which.bat na 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 

ten bat działa dobrze, dopóki nie znajdę dziwne zachowanie dzisiaj.

Jest plik O:\temp\pfiles (x86)\mystuff.txt i PATH ma zawartość:

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

Running which mystuff.txt, mam bardzo dziwne wyjściowe:

\mystuff.txt was unexpected at this time. 

enter image description here

po pewnym wywiercenie , Uważam, że nazwa katalogu (x86) powoduje, że th e problem. Aby obejść ten problem, muszę dodać cytaty do echo, tak:

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

Wadą takiego dostrojenia jest oczywista: Cytaty są drukowane na ekranie, co nie zawsze jest pożądane w opinii programisty.

Czy ktoś może pomóc wyjaśnić to dziwne zachowanie?

Problem ten znajduję, ponieważ w moim prawdziwym środowisku mam ścieżki takie jak C:\Program Files (x86)\Common Files\NetSarang w PATH, które wykazują dokładnie ten sam objaw.

enter image description here

+0

Dziękuję za poinformowanie mnie. '' where.exe'' jest świetny. Używam which.bat od Windows XP, gdzie nie ma jeszcze '' where.exe''. –

+0

dobre informacje ... ale jeśli szukasz "pliku wykonywalnego" i nie zapewniasz rozszerzenia, to nie działa ... użyj "where.exe", a następnie ... lub "które" jeśli jesteś w systemie Linux ... lub wystarczy zainstalować Cygwin i użyć "co" ... działa świetnie !!! – ZEE

Odpowiedz

8

MS Dos jest dość prosta implementacja powłoki, a kiedy zorientowali się, że interpretacja jednej linii komend DOS idzie w 2 etapach:

  1. oceny zmiennych w bieżącej linii
  2. interpretacja ocenianej linii poleceń:

W tym przypadku linia komend:

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

będzie interpretowane jako:

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 
    ) 

Teraz możemy zauważyć problem w (x86), czyli interpreter widzi to jakoś tak - najpierw ) zamyka else:

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

Rozwiązanie: wstaw "" wokół wszystkich potencjalnie problematycznych zmiennych.

I zazwyczaj umieścić cudzysłowy wokół całej zawartości polecenia echo, na przykład:

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

Naprawdę konkretne wyjaśnienie. –

2

mogę domyślać się wyjaśnieniem (choć nie jako jeden): parser cmd.exe nie jest bardzo mądry - to zostajemy zdezorientowani przez parens w %~$PATH:1 - kiedy rozszerza zmienną i widzi znak ), zakłada, że ​​jest to parenklos dla linii .(Myślę, że nie robi nic z postacią ( w rozszerzeniu, ponieważ są one znaczące tylko na początku polecenia).

Można obejść ten problem, upewniając się, że expansing które mogą zawierać „)” nie jest wewnątrz (...) poleceń grupy, lub że jest on cytowany (jak stwierdzono). Skoro nie chcesz cytaty, inne obejście może wyglądać następująco:

@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 

Jest brzydki, ale to takie rzeczy trzeba robić z cmd.exe skryptów.

4

Ponieważ problem jest teraz jasny (od Michaela Burra i Roberta Lujo), staram się pokazać rozwiązanie.

Potrzebujesz wycen, ale nie chcesz ich wyświetlać.

z opóźnionym ekspansji nawias zamykający jest nieszkodliwy

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! 
    ) 

Albo po prostu z zanikającego cytatem

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

Metoda EnableDelayedExpansion jest mniej kłopotliwa. Dziękuję Ci. –

+1

Wow, '' set "found = 1" '' jest identyczne z '' set found = 1'', ​​świetna wskazówka. –

Powiązane problemy