2013-05-13 2 views
6

У меня есть which.bat на 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 

Эта летучая мышь работает хорошо, пока я не нашел странное поведение сегодня.

Существует файл O:\temp\pfiles (x86)\mystuff.txt и PATH имеет содержание:

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

Запуск which mystuff.txt, я получил очень странный выход:

\mystuff.txt was unexpected at this time. 

enter image description here

После некоторых ковыряться , Я обнаружил, что (x86) в имени каталога вызывает th e проблема. Чтобы решить эту проблему, я должен добавить кавычки в echo, как это:

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

Недостаток такой подстройки очевидна: Котировки выводятся на экран, который не всегда нужные, по мнению программиста.

Может ли кто-нибудь помочь объяснить это странное поведение?

Я нахожу эту проблему, потому что в моем реальном env у меня есть некоторые пути, такие как C:\Program Files (x86)\Common Files\NetSarang в PATH, которые показывают точно такой же симптом.

enter image description here

+0

Благодарим Вас за давая мне знать. '' where.exe'' отлично. Я использовал which.bat с Windows XP, где еще нет '' where.exe''. –

+0

хорошая информация ... но если вы ищете «исполняемый файл» и не предоставляете расширение, то не работает ... используйте «where.exe» then ... или «which», если ou находятся в linux ... или просто установите Cygwin и используйте «который» ... отлично работает !!! – ZEE

ответ

8

MS Dos довольно простая реализация оболочки, и, как я понял, что интерпретация одной командной строки DOS проходит в 2 этапа:

  1. оценки переменных в текущей строке
  2. интерпретация оцененной командной строки

В этом случае ваша командная строка:

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

будет истолковано как:

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 
    ) 

Теперь мы можем заметить проблему в (x86), т.е. интерпретатор видит это как-то, как это - первый ) закрывает еще заявление:

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

Решение: поместите "вокруг всех потенциально проблематичных переменных.

Я обычно ставлю кавычки вокруг всего содержания команды эхо, например:

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

Действительно конкретные объяснения. –

2

Я догадываюсь при объяснении (хотя и не полезно один): анализатор CMD.exe является не очень умный - это путается parens в %~$PATH:1 - когда он расширяет переменную и видит символ ), он предполагает, что это замыкающий пар для линии .(Я думаю, что он ничего не делает с символом ( в расширении, потому что это очень важно в начале команды).

Вы можете решить эту проблему, убедившись, что расширение, которое может содержать ')', не находится внутри группы команд (...) или что оно указано (как вы нашли). Поскольку вы не хотите кавычки, другой обходной путь может выглядеть следующим образом:

@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 

Это некрасиво, но это такая вещь, что вам нужно сделать с cmd.exe сценариев.

4

Поскольку проблема сейчас понятна (от Майкла Берра и Роберта Луджо), я пытаюсь показать решение.

Вам нужны кавычки, но вы не хотите их отображать.

С задержкой расширения закрывающая скобка безвреден

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

Или просто с исчезающей цитатой

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

Метод EnableDelayedExpansion менее запутан. Спасибо. –

+1

Ничего себе, '' set 'found = 1 "' 'идентичен' 'set found = 1'', ​​отличный хитрый совет. –

Смежные вопросы