2013-05-13 3 views
6

Ich habe einen which.bat auf 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 

Diese Fledermaus funktioniert gut, bis ich ein seltsames Verhalten heute finden.

Es gibt eine Datei O:\temp\pfiles (x86)\mystuff.txt und PATH hat Inhalt:

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

which mystuff.txt Rennen, bekam ich die sehr seltsam Ausgang:

\mystuff.txt was unexpected at this time. 

enter image description here

Nach einigem Stochern Finde ich, dass der (x86) im Verzeichnisnamen th verursacht Das Problem. Um dieses Problem zu umgehen habe ich Zitate fügen dem echo, wie folgt aus:

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

Der Nachteil solcher zwicken ist offensichtlich: Die Zitate auf Bildschirm gedruckt werden, die nicht immer in der Programmierer Meinung erwünscht ist.

Kann jemand helfen, dieses merkwürdige Verhalten zu erklären?

Ich finde dieses Problem, weil in meinem realen env, habe ich einige Wege wie C:\Program Files (x86)\Common Files\NetSarang in PATH, die genau das gleiche Symptom zeigen.

enter image description here

+0

Danke, dass Sie mich kennen. '' where.exe'' ist großartig. Ich benutze which.bat seit Windows XP, wo es noch keine '' wher.exe'' gibt. –

+0

gute Info ... aber wenn Sie für eine 'ausführbare Datei' suchen und keine Erweiterung zur Verfügung stellen, dann funktioniert das nicht ... benutzen Sie 'wher.exe' dann ... oder 'was' wenn Sie in Linux sind ... oder installiere einfach Cygwin und benutze 'which' ... funktioniert super !!! – ZEE

Antwort

8

MS Dos ist ziemlich einfache Shell-Implementierung, und als ich herausgefunden habe, dass Auslegung einer DOS-Kommandozeile geht in zwei Phasen:

  1. Auswertung von Variablen in der aktuellen Zeile
  2. Interpretation der ausgewerteten Befehlszeile

In diesem Fall Ihre Befehlszeile:

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

würde interpretiert als:

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 
    ) 

Jetzt können wir das Problem in (x86) bemerken, sieht also Dolmetscher das irgendwie so - erste ) else-Anweisung schließt:

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

Lösung: Setzen Sie "" um alle potentiell problematischen Variablen.

ich in der Regel setze Anführungszeichen um den gesamten Echobefehlsinhalt, zum Beispiel:

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

Wirklich konkrete Erklärung. –

2

ich eine Erklärung erraten kann (wenn auch nicht hilfreich eins): cmd.exe der Parser nicht sehr klug ist - es wird durch die parens in %~$PATH:1 verwirrt - wenn es die Variable erweitert und sieht das ) Zeichen, nimmt es an, dass es der Closig paren für die Linie ist.(Ich denke, es macht nichts mit dem ( Zeichen in der Erweiterung, weil diese nur am Anfang eines Befehls wichtig sind).

Sie können das Problem umgehen, indem Sie sicherstellen, dass das Expansing, das ein ')' enthalten kann, nicht in einer (...) Befehlsgruppierung enthalten ist oder dass es (wie Sie gefunden haben) zitiert wird. Da Sie nicht die Anführungszeichen wollen, die andere Abhilfe könnte wie folgt aussehen:

@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 

Es ist hässlich, aber das ist die Art von Sache, die Sie mit cmd.exe Scripting zu tun haben.

4

Da das Problem jetzt klar ist (von Michael Burr und Robert Lujo), versuche ich eine Lösung zu zeigen.

Sie benötigen Anführungszeichen, aber Sie möchten sie nicht anzeigen.

Mit verzögert Expansion der schließende Klammer ist harmlos

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

Oder nur mit einem verschwindenden Zitat

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

Die EnableDelayedExpansion-Methode ist weniger verwirrend. Vielen Dank. –

+1

Wow, "set" found = 1 "' 'ist identisch mit' 'set found = 1'', ​​toller Tipp. –