Spazi e parentesi in Windows La variabile PATH rovina i file batch


14

Quindi, la mia variabile di percorso (Sistema-> Impostazioni avanzate-> Env Vars-> Sistema-> PERCORSO) è impostata su:

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;

Anche se, ovviamente, senza le nuove linee.

Notare le righe che contengono PathWithSpaces- il primo non ha spazi, il secondo ha uno spazio, e la terza ha uno spazio seguita da una parentesi.

Ora nota l'output di questo file 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;"

o in particolare la linea:

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

Allora, cos'è questa stronzata?

In particolare:

  • Directory nel percorso correttamente sfuggita alle virgolette, ma senza spazi = fine
  • Directory nel percorso correttamente sfuggita alle virgolette e con spazi ma nessuna parentesi = fine
  • Directory nel percorso correttamente sfuggita alle virgolette, con spazi e una parentesi = ERRORE

Cosa sta succedendo qui? Come posso risolvere questo problema? Probabilmente ricorrere a un punto di giunzione per lasciare che i miei strumenti funzionino ancora come soluzione alternativa, ma se hai qualche idea su questo, per favore fammi sapere :)


Sulla base della mia comprensione dei problemi in corso, la risposta sopra è quella corretta e si basa sul prendere in considerazione che SET è il comando e PATH fa parte del suo argomento, il cui bilancio è la nuova stringa PATH. Quindi, IMO, non è che sia scarsamente documentato, ma che è più simile a un caso oscuro. Ho appena trascorso un paio d'ore su questo problema.
David A. Gray,

Risposte:


13

Questo può accadere se ci sono parentesi senza escape in una riga all'interno di un "blocco" (che utilizza anche parentesi per la delimitazione).

Di solito è possibile risolverlo attivando l'espansione ritardata e utilizzare le variabili con !var!invece di %var%. Non ci sono molti altri consigli che posso dare senza vedere il codice.



13

Non ci dovrebbero essere (a) non ci sono virgolette nella variabile ambientale PATH di MS-Windows (comando PATH) o (b) ci dovrebbero essere virgolette che circondano l'intera espressione dopo il (comando SET) . Sfortunatamente, questo non è ben documentato da MS, anche se affermano che se vengono utilizzate le virgolette, saranno incluse nel valore della variabile (Riferimento da riga di comando di Windows XP) .

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

Ciò può causare problemi incoerenti e quindi difficili da diagnosticare. Ad esempio, se il tuo percorso include "C: \ Python27", la tua macchina dirà "'python' non è riconosciuto come comando interno o esterno, programma eseguibile o file batch." quando si tenta di eseguire Python. Tuttavia, alcune librerie potrebbero essere ancora disponibili.

Non è necessario "sfuggire" a spazi o parentesi. Se devi evitare caratteri speciali, inserisci le virgolette intorno all'intera espressione, incluso il nome della variabile.

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

oppure puoi usare anche le parentesi.

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

Nota, le virgolette doppie devono venire in coppia.

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

Tuttavia, probabilmente non sono presenti caratteri validi per i percorsi, che potrebbero causare problemi con il comando SET.



1
In realtà hai scritto MS-DOS quando intendevi MS-Windows e i tuoi comandi erano per MS-Windows. L'OP ha chiesto informazioni su MS-Windows. Quindi non lo so perché lo chiami MS-DOS. Perfino i tuoi collegamenti dicevano NT (ovvero Windows. Prima era 9X e NT, ora è solo NT). Windows e MS-DOS sono due sistemi operativi diversi. Ho visto il prompt dei comandi di Windows erroneamente chiamato DOS prima, ma anche quello non è sbagliato come quello che lo hai chiamato.
barlop

@barlop, ovviamente hai ragione. Grazie per le modifiche. Fino a Windows-95, Windows era un'applicazione basata su DOS. È possibile avviare Windows digitando il wincomando in DOS. In effetti prima di Windows-3.1, tutto, come Zork e WordStar, erano applicazioni DOS. Quindi a partire da Windows-98, non c'era DOS. Ma penso che alcuni vecchi timer come me si riferiscano ancora erroneamente alla shell CMD come a una shell DOS. Ci scusiamo per la confusione e grazie ancora per aver chiarito l'intento della mia risposta.
Mark Mikofski,

@MarkMikofski In realtà Windows 9X (95/98 / ME) è stato probabilmente costruito anche su DOS. Ad esempio, potresti modificare alcuni file (forse msdos.sys) alcune opzioni come bootGUI = 0 e interrompere il caricamento di windows tokyopc.org/newsletter/1996/08/msdosed.html Se è possibile caricare Windows da lì, non posso ' non lo so. E un disco di avvio di Win9X è considerato DOS. I vecchi timer che sanno di cosa stanno parlando, di solito sono le ultime persone a fare l'errore di chiamare il prompt dei comandi di Windows DOS. E sono le prime persone ad essere più irremovibili che non si tratti di DOS.
barlop

1
Hai provato a consigliare (SET PATH=%PATH%;C:\Program Files (x86)\path with special characters)? È totalmente sbagliato!
JosefZ,

2

Microsoft documenta il problema in " Errore durante l'esecuzione degli script della shell dei comandi che includono parentesi ".

La soluzione che suggeriscono è quella di utilizzare l'espansione ritardata.

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

Per impostare un percorso in un blocco if, anziché utilizzare SET PATH=, è consigliabile utilizzare il PATHcomando.

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

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

Per altre variabili, un'altra soluzione potrebbe essere quella di utilizzare le virgolette, ma intorno a tutto:

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

1

Joey nella sua risposta dice

Questo può accadere se ci sono parentesi senza escape in una riga all'interno di un "blocco" (che utilizza anche parentesi per la delimitazione).

e questo è vero. Se ci sono parentesi senza caratteri di escape, dovresti evitarle. Questo è quello che ho fatto; Ho sostituito

set PATH=some_path;%PATH%

con

set PATH="some_path;%PATH%"

e questo ha risolto il problema.


2
No. Dovresti usareset "PATH=some_path;%PATH%"
JosefZ il

1

Ho sperimentato qualcosa di simile. Microsoft spiega il problema qui: http://support.microsoft.com/kb/329308

Fondamentalmente, invece di cambiare la variabile Path tramite System-> Adv Settings-> Env Vars-> System-> PATH, prova

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

1

In Windows 8 ho riscontrato scarso successo con uno di questi metodi. Le parentesi non funzionano, le virgolette funzionano, ma il "percorso" modificato in questo modo non è il percorso utilizzato per l'individuazione degli eseguibili, ma cmdsembra comunque utilizzare il percorso di sistema ereditato all'apertura della finestra.

esempio: dopo aver determinato l'architettura del processore, voglio aggiungere un paio di percorsi alla variabile d'ambiente PATH. In realtà, anche solo aggiungerli temporaneamente funzionerebbe dal momento che ho solo bisogno di loro mentre è in esecuzione un file batch. Ma non funziona nemmeno.

echo %path%visualizza il PERCORSO di sistema al momento del cmdlancio.

set path="%path%;%programfiles(x86)%\company\program\subdir"funziona ma ora %path%contiene tutto racchiuso tra virgolette e se provo a eseguire un programma in subdir da qualche altra parte, non riesce. L'uso delle parentesi attorno a tutto anziché le virgolette non funziona .

Un'altra cosa che ho notato è che lo stesso comando funzionerà se immesso in modo interattivo cmd, ma non se rilevato in un file batch. È spaventoso. Ancora un'altra stranezza è la perdita intermittente dell'ultimo carattere del valore di una variabile d'ambiente! Un'altra incoerenza è con i programmi di terze parti: alcuni possono gestire un %var%come parametro, altri no.


1

Ho avuto grossi problemi a far funzionare il seguente in Win8 fino a quando ho aggiunto virgolette attorno al valore che stavo impostando sulla variabile fromFile. Senza di ciò, quando fromFile conteneva un nome file con parentesi, la riga successiva che stava tentando di fare la sostituzione di stringa per generare la variabile toFile stava fallendo. Nota che uso lì un'espansione ritardata per valutare la variabile al momento dell'esecuzione anziché al momento dell'analisi (della rispettiva istanza 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.