Espaces et parenthèses dans la variable PATH de Windows visse les fichiers batch


14

Ainsi, ma variable de chemin (System-> Adv Settings-> Env Vars-> System-> PATH) est définie sur:

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;

Bien sûr, sans les nouvelles lignes.

Notez que les lignes contenant PathWithSpaces- le premier n'a pas les espaces, la deuxième a un espace, et la troisième a un espace suivi d'une parenthèse.

Maintenant, notez la sortie de ce fichier batch:

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 plus précisément la ligne:

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

Alors, quelle est cette connerie?

Plus précisément:

  • Répertoire dans un chemin correctement échappé avec des guillemets, mais sans espace = bien
  • Répertoire dans un chemin qui est correctement échappé avec des guillemets et qui contient des espaces mais pas de parenthèses = fine
  • Répertoire dans le chemin qui est correctement échappé avec des guillemets, et a des espaces et a une parenthèse = ERREUR

Que se passe t-il ici? Comment puis-je réparer cela? Je vais probablement recourir à un point de jonction pour laisser mes outils fonctionner comme solution de contournement, mais si vous avez un aperçu de cela, faites-le moi savoir :)


Sur la base de ma compréhension des problèmes à résoudre, la réponse ci-dessus est la bonne, et elle repose sur la prise en compte du fait que SET est la commande, et PATH fait partie de son argument, le reste étant la nouvelle chaîne PATH. Donc, l'OMI, ce n'est pas qu'il soit peu documenté, mais plutôt comme un cas de bord obscur. Je viens de passer quelques heures sur cette question.
David A. Gray

Réponses:


13

Cela peut se produire s'il y a des parenthèses non échappées dans une ligne à l'intérieur d'un "bloc" (qui utilise également des parenthèses pour délimiter).

Vous pouvez généralement le corriger en activant l'expansion différée et en utilisant des variables avec !var!au lieu de %var%. Il n'y a pas beaucoup plus de conseils que je pourrais donner sans voir le code.



13

Il ne doit y avoir (a) pas de guillemets dans la variable d'environnement MS-Windows PATH (commande PATH) ou (b) il doit y avoir des guillemets entourant l'expression entière après la (commande SET) . Malheureusement, cela n'est pas très bien documenté par MS, bien qu'ils indiquent que si des guillemets sont utilisés, ils seront inclus dans la valeur de la variable (référence de ligne de commande Windows XP) .

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

Cela peut entraîner des problèmes incohérents et donc difficiles à diagnostiquer. Par exemple, si votre chemin inclut "C: \ Python27", votre machine dira "" python "n'est pas reconnu comme une commande interne ou externe, un programme exploitable ou un fichier de commandes." lorsque vous essayez d'exécuter python. Cependant, certaines bibliothèques peuvent toujours être disponibles.

Vous n'avez pas besoin de "fuir" les espaces ou les parenthèses. Si vous devez échapper des caractères spéciaux, placez des guillemets autour de l'expression entière, y compris le nom de la variable.

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

ou vous pouvez également utiliser des parenthèses.

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

Remarque: les guillemets doubles doivent être fournis par paires.

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

Cependant, il n'y a probablement pas de caractères qui sont des chemins d'accès valides, ce qui provoquerait un problème avec la commande SET.



1
Vous avez en fait écrit MS-DOS lorsque vous vouliez dire MS-Windows, et vos commandes étaient pour MS-Windows. L'OP a posé des questions sur MS-Windows. Alors pourquoi vous l'appelez MS-DOS, je ne sais pas. Même vos liens indiquaient NT (c'est-à-dire Windows. Auparavant, c'était 9X et NT, maintenant c'est juste NT). Windows et MS-DOS sont deux systèmes d'exploitation différents. J'ai déjà vu l'invite de commande Windows appelée par erreur DOS, mais même cela n'est pas aussi faux que ce que vous l'appeliez.
barlop

@barlop, bien sûr, vous avez raison. Merci pour les modifications. Jusqu'à Windows 95, Windows était une application basée sur DOS. Vous pouvez démarrer Windows en tapant la wincommande sous DOS. En fait, avant Windows-3.1, tout, comme Zork et WordStar, étaient des applications DOS. Puis à partir de Windows 98, il n'y avait pas de DOS. Mais je pense que certains anciens temporisateurs comme moi se réfèrent toujours à tort au shell CMD comme un shell DOS. Désolé pour la confusion, et merci encore d'avoir clarifié l'intention de ma réponse.
Mark Mikofski

@MarkMikofski En fait, Windows 9X (95/98 / ME) était sans doute également construit sur DOS. Vous pouvez par exemple éditer un fichier (peut-être msdos.sys) des options comme bootGUI = 0 et arrêter le chargement des fenêtres tokyopc.org/newsletter/1996/08/msdosed.html Si vous pouvez ensuite charger des fenêtres à partir de là, je ne le fais pas '' t sais. Et un disque de démarrage Win9X est considéré comme DOS. Les anciens temporisateurs qui savent de quoi ils parlent comme vous, sont généralement les derniers à commettre l'erreur d'appeler l'invite de commande Windows DOS. Et sont les premières personnes à être les plus convaincues que ce n'est pas DOS.
barlop

1
Avez-vous essayé conseillé (SET PATH=%PATH%;C:\Program Files (x86)\path with special characters)? C'est totalement faux!
JosefZ

2

Microsoft documente le problème dans « Erreur lors de l'exécution des scripts de shell de commande contenant des parenthèses ».

La solution qu'ils suggèrent est d'utiliser une expansion retardée.

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

Pour définir un chemin dans un bloc if, plutôt que d'utiliser SET PATH=, vous devriez probablement utiliser la PATHcommande.

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

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

Pour les autres variables, une autre solution peut être d'utiliser des guillemets, mais autour du tout:

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

1

Joey dans sa réponse dit

Cela peut se produire s'il y a des parenthèses non échappées dans une ligne à l'intérieur d'un "bloc" (qui utilise également des parenthèses pour délimiter).

et c'est vrai. S'il y a des parenthèses non échappées, il faut bien y échapper. C'est ce que j'ai fait; j'ai remplacé

set PATH=some_path;%PATH%

avec

set PATH="some_path;%PATH%"

et cela a résolu le problème.


2
Nan. Vous devez utiliserset "PATH=some_path;%PATH%"
JosefZ

1

J'ai vécu quelque chose de similaire. Microsoft explique le problème ici: http://support.microsoft.com/kb/329308

Fondamentalement, au lieu de changer la variable Path via System-> Adv Settings-> Env Vars-> System-> PATH, essayez

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

1

Dans Windows 8, j'ai rencontré très peu de succès avec l'une de ces méthodes. Les parenthèses ne fonctionnent pas, les guillemets fonctionnent, mais le «chemin» que vous modifiez de cette façon n'est pas le chemin utilisé pour localiser les exécutables, mais cmdsemble toujours utiliser le chemin système dont il a hérité lorsque vous avez ouvert la fenêtre.

exemple: après avoir déterminé l'architecture du processeur, je veux ajouter quelques chemins à la variable d'environnement PATH. En fait, même les ajouter temporairement fonctionnerait car je n'en ai besoin que lorsqu'un fichier de commandes est en cours d'exécution. Mais ça ne marche même pas.

echo %path%affiche le système PATH au moment du cmdlancement.

set path="%path%;%programfiles(x86)%\company\program\subdir"fonctionne mais %path%contient maintenant tout ce qui est entouré de guillemets, et si j'essaie d'exécuter un programme dans subdir ailleurs, il échoue. L'utilisation de parenthèses autour de l'ensemble au lieu de guillemets ne fonctionne pas .

Une autre chose que j'ai remarquée est que la même commande fonctionnera si elle est entrée de manière interactive dans cmd, mais pas si elle est rencontrée dans un fichier batch. C'est effrayant. Encore une autre bizarrerie est la perte intermittente du dernier caractère de la valeur d'une variable d'environnement! Une autre incohérence concerne les programmes tiers: certains peuvent gérer %var%un paramètre, d'autres pas.


1

J'ai eu beaucoup de mal à faire le travail suivant dans Win8 jusqu'à ce que j'ajoute des guillemets doubles autour de la valeur que je définissais pour la variable fromFile. Sans cela, lorsque fromFile contenait un nom de fichier avec des parenthèses, la ligne suivante qui essayait de faire une substitution de chaîne pour générer la variable toFile échouait. Notez que j'utilise l'expansion retardée pour évaluer la variable au moment de l'exécution plutôt qu'au moment de l'analyse (de l'instance CALL respective)

::-- 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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.