Espaços e parênteses na variável PATH do Windows estraga arquivos em lote


14

Portanto, minha variável de caminho (Sistema-> Configurações Avançadas-> Env Vars-> Sistema-> PATH) está definida como:

C:\Python26\Lib\site-packages\PyQt4\bin;
%SystemRoot%\system32;
%SystemRoot%;
%SystemRoot%\System32\Wbem;
%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;
C:\Python26\;
C:\Python26\Scripts\;
C:\cygwin\bin;
"C:\PathWithSpaces\What_is_this_bullshit";
"C:\PathWithSpaces 1.5\What_is_this_bullshit_1.5";
"C:\PathWithSpaces (2.0)\What_is_this_bullshit_2.0";
"C:\Program Files (x86)\IronPython 2.6";
"C:\Program Files (x86)\Subversion\bin";
"C:\Program Files (x86)\Git\cmd";
"C:\Program Files (x86)\PuTTY";
"C:\Program Files (x86)\Mercurial";
Z:\droid\android-sdk-windows\tools;

Embora, obviamente, sem as novas linhas.

Observe as linhas que contêm PathWithSpaces- a primeira não possui espaços, a segunda possui um espaço e a terceira possui um espaço seguido por parênteses.

Agora, observe a saída deste arquivo em lotes:

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\>vcvars32.bat
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>"C:\Program Files (x86
)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
Setting environment for using Microsoft Visual Studio 2008 x86 tools.
\What_is_this_bullshit_2.0";"C:\Program was unexpected at this time.
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin>      set "PATH=C:\Pro
gram Files\Microsoft SDKs\Windows\v6.0A\bin;C:\Python26\Lib\site-packages\PyQt4\
bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\
WindowsPowerShell\v1.0\;C:\Python26\;C:\Python26\Scripts\;C:\cygwin\bin;"C:\Path
WithSpaces\What_is_this_bullshit";"C:\PathWithSpaces 1.5\What_is_this_bullshit_1
.5";"C:\PathWithSpaces (2.0)\What_is_this_bullshit_2.0";"C:\Program Files (x86)\
IronPython 2.6";"C:\Program Files (x86)\Subversion\bin";"C:\Program Files (x86)\
Git\cmd";"C:\Program Files (x86)\PuTTY";"C:\Program Files (x86)\Mercurial";Z:\dr
oid\android-sdk-windows\tools;"

ou especificamente a linha:

\What_is_this_bullshit_2.0";"C:\Program was unexpected at this time.

Então, o que é essa besteira?

Especificamente:

  • Diretório no caminho que é escapado corretamente entre aspas, mas sem espaços = fino
  • Diretório no caminho que é escapado corretamente entre aspas e possui espaços, mas sem parênteses = fino
  • Diretório no caminho que é escapado corretamente entre aspas e possui espaços e parênteses = ERRO

O que está acontecendo aqui? Como posso consertar isso? Provavelmente vou recorrer a um ponto de junção para permitir que minhas ferramentas ainda funcionem como solução alternativa, mas se você tiver alguma idéia, informe-me :)


Com base na minha compreensão dos problemas em questão, a resposta acima é a correta e ela leva em consideração que SET é o comando e PATH é parte de seu argumento, cujo saldo é a nova sequência PATH. Então, IMO, não é que seja escassamente documentado, mas que seja mais como um caso obscuro. Passei algumas horas nessa questão.
David A. Gray

Respostas:


13

Isso pode acontecer se houver parênteses sem escape em uma linha dentro de um "bloco" (que também usa parênteses para delimitar).

Geralmente, você pode corrigi-lo ativando a expansão atrasada e usando variáveis ​​em !var!vez de %var%. Não há muito mais conselhos que eu poderia dar sem ver o código.



13

(A) não deve haver aspas na variável de ambiente PATH do MS-Windows (comando PATH) ou (b) deve haver aspas em torno de toda a expressão após o (comando SET) . Infelizmente, isso não está muito bem documentado pela MS, embora eles afirmem que, se as aspas forem usadas, elas serão incluídas no valor da variável (Referência de Linha de Comando do Windows XP) .

$ SET BLAH="blah blah(1)"
$ ECHO %BLAH%
"blah blah(1)"
$ SET BLAH=blah blah(1)
$ ECHO %BLAH%
blah blah(1)

Isso pode causar problemas inconsistentes e, portanto, difíceis de diagnosticar. Por exemplo, se o seu caminho incluir "C: \ Python27", sua máquina dirá "'python' não é reconhecido como um comando interno ou externo, programa operável ou arquivo em lotes". quando você tenta executar python. No entanto, algumas bibliotecas ainda podem estar disponíveis.

Você não precisa "escapar" de espaços ou parênteses. Se você precisar escapar de caracteres especiais, coloque aspas em toda a expressão, incluindo o nome da variável.

SET "PATH=%PATH%;C:\Program Files (x86)\path with special characters"

ou você pode usar parênteses também.

(SET VAR=can't contain ampersand, parentheses, pipe, gt or lt)

Observe que aspas duplas devem vir em pares.

(SET VAR=illegal characters!@#$%^*_-+={}[]\:;""',./?)
echo %VAR%
illegal characters!@#$%*_-+={}[]\:;""',./?

No entanto, provavelmente não existem caracteres com nomes de caminho válidos, o que causaria um problema com o comando SET.



1
Você realmente escreveu o MS-DOS quando quis dizer o MS-Windows e seus comandos foram para o MS-Windows. O OP perguntou sobre o MS-Windows. Então, por que você está chamando de MS-DOS, eu não sei. Até seus links diziam NT (ou seja, Windows. Costumava ser 9X e NT, agora é apenas NT). Windows e MS-DOS são dois sistemas operacionais diferentes. Eu já vi o prompt de comando do Windows chamado DOS erroneamente antes, mas mesmo isso não é tão errado quanto o que você chamou.
Barlop

@ Barlop, é claro que você está correto. Obrigado pelas edições. Até o Windows 95, o Windows era um aplicativo criado sobre o DOS. Você pode iniciar o Windows digitando o wincomando no DOS. De fato, antes do Windows 3.1, tudo, como o Zork e o WordStar, eram aplicativos do DOS. Então, começando com o Windows 98, não havia DOS. Mas acho que alguns timers antigos como eu ainda se referem ao shell do CMD por engano como um shell do DOS. Desculpe a confusão e obrigado novamente por esclarecer a intenção da minha resposta.
Mark Mikofski

@MarkMikofski Na verdade, o Windows 9X (95/98 / ME) também foi baseado no DOS. Você pode, por exemplo, editar um arquivo (talvez msdos.sys), algumas opções, como bootGUI = 0, e parar o carregamento do Windows em tokyopc.org/newsletter/1996/08/msdosed.html Se você pode carregar o Windows a partir daí, eu não ' não sei. E um disco de inicialização do Win9X é considerado DOS. Os veteranos que sabem do que estão falando, como você, geralmente são as últimas pessoas a cometer o erro de chamar o prompt de comando do Windows, DOS. E são as primeiras pessoas a serem mais inflexíveis quanto ao fato de não ser DOS.
barlop

1
Você tentou aconselhar (SET PATH=%PATH%;C:\Program Files (x86)\path with special characters)? Está totalmente errado!
11119 JosefZ

2

A Microsoft documenta o problema em " Erro ao executar scripts de shell de comando que incluem parênteses ".

A solução que eles sugerem é usar a expansão atrasada.

SETLOCAL ENABLEDELAYEDEXPANSION
SET VAR=string containing ( and ) ...
IF "y" == "y" (
    ECHO !VAR! %VAR%
)
ENDLOCAL

Para definir um caminho em um bloco if, em vez de usar SET PATH=, você provavelmente deve usar o PATHcomando

SET AddToPath=C:\Program Files (x86)\Whatever

SETLOCAL ENABLEDELAYEDEXPANSION
IF "%X%" == "%Y%" (
    ECHO Adding !AddToPath! to path !PATH!
    PATH !AddToPath!;!PATH!
)

Para outras variáveis, outra solução pode ser usar aspas, mas em torno da coisa toda:

SET "MyVar=C:\Program Files (x86)\Whatever"

1

Joey em sua resposta diz

Isso pode acontecer se houver parênteses sem escape em uma linha dentro de um "bloco" (que também usa parênteses para delimitar).

e isso é verdade. Se houver parênteses sem escape, deve-se escapar deles. Isso é o que eu fiz; Eu troquei

set PATH=some_path;%PATH%

com

set PATH="some_path;%PATH%"

e isso resolveu o problema.


2
Não. Você deve usarset "PATH=some_path;%PATH%"
JosefZ

1

Eu experimentei algo semelhante. A Microsoft explica o problema aqui: http://support.microsoft.com/kb/329308

Basicamente, em vez de alterar a variável Path via Sistema-> Configurações Avançadas-> Env Vars-> Sistema-> PATH, tente

My Computer->Manage->Computer Management (local)-> Properties-> Advanced-> Environment variables-> Settings

1

No Windows 8, encontrei muito pouco sucesso com qualquer um desses métodos. Parênteses não funcionam, aspas funcionam, mas o "caminho" que você modifica dessa maneira não é o caminho usado para localizar executáveis, mas cmdainda parece estar usando o caminho do sistema que herdou quando você abriu a janela.

exemplo: após determinar a arquitetura do processador, desejo adicionar alguns caminhos à variável de ambiente PATH. Na verdade, apenas adicioná-los temporariamente funcionaria, pois eu só preciso deles enquanto um arquivo em lote está em execução. Mas isso nem funciona.

echo %path%exibe o PATH do sistema no momento em que cmdfoi lançado.

set path="%path%;%programfiles(x86)%\company\program\subdir"funciona, mas agora %path%contém tudo entre aspas, e se eu tentar executar um programa em subdiretório de outro lugar, ele falhará. Usar parênteses ao redor da coisa toda em vez de aspas não funciona .

Outra coisa que notei é que o mesmo comando funcionará se for inserido interativamente cmd, mas não se for encontrado em um arquivo em lotes. Isso é assustador. Ainda outra singularidade é a perda intermitente do último caractere do valor de uma variável de ambiente! Outra inconsistência é com programas de terceiros: alguns podem manipular a %var%como parâmetro, outros não.


1

Eu tive um grande problema ao fazer o seguinte trabalho no Win8 até adicionar aspas duplas ao redor do valor que eu estava definindo para a variável fromFile. Com isso, quando fromFile continha um nome de arquivo com parênteses, a próxima linha que tentava fazer a substituição de string para gerar a variável toFile estava falhando. Observe que eu uso a expansão atrasada para avaliar a variável no tempo de execução em vez de no tempo de análise (da respectiva instância CALL)

::-- BATCH file that creates an *_576_5.* file from an *_640_t.* one (copying it)
::-- Author: George Birbilis (http://zoomicon.com)
::-- Credits: String replacement based on http://www.dostips.com/DtTipsStringManipulation.php

@ECHO OFF

::-- Loop for all files recursively --::

FOR /R %%f in (*_640_t.*) DO CALL :process %%f

ECHO(
PAUSE

GOTO :EOF

::-- Per-file actions --::

:process

:: Display progress...
::ECHO Processing %*
<nul (set/p dummy=.)

SETLOCAL ENABLEDELAYEDEXPANSION
SET fromFile="%*"
SET toFile=!fromFile:_640_t=_576_t!

IF NOT EXIST %toFile% CALL :generate %fromFile% %toFile%

GOTO :EOF

::-- Generate missing file --::

:generate

ECHO(
ECHO COPY %*
COPY %*

::PAUSE

GOTO :EOF
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.