2013-05-13 9 views
6

Ho un which.bat su 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 

Questo pipistrello funziona bene fino a quando ho trovato uno strano comportamento di oggi.

è presente un file O:\temp\pfiles (x86)\mystuff.txt, e PATH ha un contenuto:

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

esecuzione which mystuff.txt, ho ottenuto il molto strano uscita:

\mystuff.txt was unexpected at this time. 

enter image description here

Dopo un po 'rovistando , Trovo che il (x86) nel nome della directory causa th e problema Per risolvere il problema, devo aggiungere citazioni al echo, in questo modo:

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

L'aspetto negativo di tale tweak è evidente: Le citazioni vengono stampate a schermo che non è sempre desiderato nel parere del programmatore.

Qualcuno può aiutare a spiegare questo strano comportamento?

Trovo questo problema perché nel mio ambiente reale, ho alcuni percorsi come C:\Program Files (x86)\Common Files\NetSarang in PERCORSO, che presentano esattamente lo stesso sintomo.

enter image description here

+0

Grazie per avermi permesso di conoscere. '' where.exe'' è fantastico. Sto usando which.bat da Windows XP dove non c'è ancora '' where.exe''. –

+0

buone informazioni ... ma se stai cercando un 'eseguibile' e non fornisci alcuna estensione, allora non funziona ... usa 'where.exe' allora ... o 'which' se sei in linux ... o installa Cygwin e usa 'which' ... funziona alla grande !!! – ZEE

risposta

8

MS Dos è piuttosto semplice implementazione di shell, e come ho capito che l'interpretazione di una riga di comando DOS va in 2 fasi:

  1. valutazione delle variabili in linea corrente
  2. interpretazione della riga di comando valutata

In questo caso la riga di comando:

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

verrebbe interpretato come:

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 
    ) 

Ora possiamo notare il problema in (x86), cioè interprete vede questo in qualche modo come questo - prima ) chiude else:

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

Soluzione: mettere "" attorno a tutte le variabili potenzialmente problematiche.

Io di solito messo tra virgolette l'intero contenuto comando echo, ad esempio:

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

Spiegazione davvero concreta. –

2

posso indovinare una spiegazione (anche se non un utile uno): parser di cmd.exe non è molto intelligente - è viene confuso dai paren in %~$PATH:1 - quando espande la variabile e vede il carattere ), si presume che sia il paren di chiusura per la riga .(Penso che non faccia nulla con il carattere ( nell'espansione perché quelli sono significativi solo all'inizio di un comando).

È possibile aggirare il problema assicurandosi che l'espansione che può contenere un ')' non sia all'interno di un gruppo di comandi (...) o che sia quotato (come è stato trovato). Dal momento che non si vuole le virgolette, l'altra soluzione potrebbe essere simile:

@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 

E 'brutto, ma questo è il genere di cose che devi fare con lo scripting cmd.exe.

4

Poiché il problema è chiaro ora (da Michael Burr e Robert Lujo), cerco di mostrare una soluzione.

Hai bisogno di preventivi, ma non vuoi visualizzarli.

Con l'espansione ritardata la parentesi di chiusura è innocuo

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

O solo con una citazione scomparsa

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

Il metodo EnableDelayedExpansion è meno confuso. Grazie. –

+1

Wow, '' set "found = 1" '' è identico a '' set found = 1'', ​​ottimo suggerimento complicato. –

Problemi correlati