2011-11-24 8 views
6

I nomi delle variabili di ambiente definiti dall'utente di Windows possono contenere qualsiasi carattere tranne =.Quale sintassi controllerà se un nome di variabile contenente spazi è definito?

È possibile includere caratteri speciali facendoli sfuggire. Un metodo più semplice consiste semplicemente nel racchiudere l'intera espressione SET tra virgolette. Ad esempio:

set "A weird & "complex" variable=My value" 
set A weird ^& "complex" variable=My value 

Entrambe le espressioni precedenti danno lo stesso risultato. Il nome della variabile è A weird & "complex" variable e il valore è My value

l'IF costrutto definita viene utilizzata per verificare se è definita una variabile. Le virgolette non funzionano per questo test, i caratteri speciali nel nome (comprese le virgolette) devono essere sfuggiti.

set "A&B=value" 
if defined A^&B echo This works 
if defined "A&B" echo This does not work 

Il test di escape sopra funziona perfettamente. Il test quotato non funziona

Ma come posso verificare se esiste una variabile contenente spazi?

set "A B=value" 
if defined A^ B echo this does not work! 

Sembra che quanto sopra dovrebbe funzionare, ma non funziona!

Sto cercando una risposta che NON implichi l'espansione della variabile utilizzando% A B% o! A B!

risposta

5

Interessante domanda (adoro queste domande sulla sintassi base).

Ovviamente si sa come controllarlo con espansione ritardata e anche i lavori di FOR-parameters.

@echo off 
setlocal 
set "AAA BBB=value" 
set ""AAA BBB"=" 
set "AAA=" 
for %%a in ("AAA BBB") do if defined %%~a echo FOR: This works 

setlocal EnableDelayedExpansion 
set "varname=AAA BBB" 
if defined !varname! echo Delayed: This works 

if defined %varname% (echo percent: Never comes here 
) ELSE (echo percent: Never comes here ?) 

if defined AAA^ BBB (echo escape1: Never comes here 
) ELSE (echo escape1: fails) 

set AAA=Hello 
if defined AAA^ BBB ( 
    echo escape2: It only test for AAA the BBB will be "removed" 
) ELSE (echo escape2: fails) 

set "space= " 
if defined AAA!space!BBB echo inject space: This works 

if defined "AAA BBB" (echo Quote1: Never comes here 
) ELSE (echo Quote1: Fails) 

set ""AAA BBB"=value" 
if defined "AAA BBB" echo Quote2: This works, it checks for "AAA BBB" with quotes 

Nella mia opionion, nell'esempio escape2 il parser prima dividere la linea in token questo modo:
<if> <defined> <AAA BBB> <echo .... Ma al tempo di esecuzione del se definiti esso riesamina la <AAA BBB> gettone così ottiene solo il AAA.
Non è possibile iniettare una seconda fuga come AAA^^^ BBB come questo solo ricerche per la variabile denominata AAA^

non riesco a vedere una soluzione senza ritardare/PER, come la fuga dello spazio fallisce sempre.

EDIT: Può anche essere risolto con SET <varname>
La soluzione ijprest utilizza il comando SET per verificare la variabile senza la necessità di sfuggire nomevar.
Ma mostra anche un comportamento interessante con gli spazi all'interno e alla fine di un varname.

Sembra di seguire queste regole:
SET varname ricerche per tutte le variabili che iniziano con varname, ma prima rimuove tutti i caratteri dopo l'ultimo carattere di spazio di varname, e rimuove tutti gli spazi iniziali.
Quindi non è possibile cercare le variabili con inizio con lo spazio (ma è anche un po 'complicato creare un tale varname).

Lo stesso comportamento è attivo anche se il nome della variabile è racchiuso tra virgolette, ma esiste ancora un'altra regola.
Prima rimuovere tutti i caratteri dopo l'ultima citazione, se ci sono almeno due citazioni. Usa il testo all'interno delle virgolette e usa la "barra".

Esempio.

set " abc def ghi" junk junk 
*** 1. removes the junk 
set " abc def ghi" 
*** 2. removes the quotes 
set  abc def ghi 
*** 3. removes all after the last space, and the trailing spaces 
set abc def 
*** Search all variables beginning with abc def 
+0

Il FOR /! Ritardare! la soluzione non era ovvia quando avevo bisogno di dormire. Ci ho pensato quando mi sono svegliato, ma hai già ricevuto una risposta eccellente! :) – dbenham

+0

L'analisi * escape2 * è molto interessante. Ancora un'altra opportunità di inserire un commento in una dichiarazione – dbenham

0

L'altro modo è quello di riassegnare ad un'altra variabile (uno senza spazi) e verificare che . Vedi qui:

rem Prepare ONLY variable 'a b' 
set "a b=123" 
echo [a b]=%a b% 

rem This will ouput: [a b] is defined 
set var=%a b% 
if defined var (
    echo [a b] is defined 
) else (
    echo [a b] is not defined 
) 

rem This will output: [c d] is not defined 
set var=%c d% 
if defined var (
    echo [c d] is defined 
) else (
    echo [c d] is not defined 
) 
+0

Ovviamente funziona, ma l'ultima esigenza della mia domanda originale affermava che stavo cercando una risposta che NON usasse% A B% o! A B !. (BTW, assegnare! A B! È molto più sicuro. L'assegnazione di% A B% può fallire a seconda dei contenuti) – dbenham

3

Mi piace anche questo tipo di domanda! :)

Ecco un'altra soluzione possibile, mi è venuta ... usando SET stesso per verificare l'esistenza, e usando il risultato ERRORLEVEL:

set "A B=foo" 
set A B >nul 2>nul&& echo 1. This works 
set "A B ">nul 2>nul&& echo 2. This works 

set "A weird & "complex" variable=foo" 
set A weird ^& "complex" variable >nul 2>nul&& echo 3. This works 
set "A weird & "complex" variable ">nul 2>nul&& echo 4. This works 

Si noti che questo funziona solo se le variabili sono unici nel senso che nessun nome di variabile è il prefisso di un altro. Altrimenti rischi di falsi positivi, in quanto il comportamento predefinito di SET è quello di mostrare tutte le variabili che iniziano con il parametro che passi. Se questo potrebbe essere il caso, si potrebbe filtrare i risultati con findstr:

set "A B=" 
set "A B C=foo" 
set "A B ">nul 2>nul&& echo 5. Failed (false positive) 
set "A B "|findstr /B /L /C:"A B=" >nul||echo 6. This works (no false positive) 

Inoltre, lo spazio singolo finale dopo il nome della variabile sembra essere necessaria. Senza di esso, SET spesso analizza erroneamente l'input. Stranamente, se aggiungi uno spazio aggiuntivo tra "2> nul" e "& &" nel caso # 3 smette di funzionare (a meno che non rimuovi lo spazio prima di "> nul") ... strano.

+0

+1 Buona soluzione con l'aggiunta di FINDSTR. Avevo pensato al test SET e l'ho rifiutato, ma non pensavo di aggiungere FINDSTR. Continuo a preferire la soluzione di jeb perché non richiede pipe o comandi esterni, quindi è più veloce. – dbenham

+0

Scoperta molto interessante sullo spazio extra richiesto altrimenti qualsiasi variabile che inizi con le corrispondenze "a". Le virgolette non sono necessarie. 'imposta un b' fallisce. 'imposta un b ' funziona. 'imposta un b ' fallisce! @ jeb - qualche idea su cosa sta succedendo qui? – dbenham

+0

Aggiungo un commento alla mia [risposta] (http://stackoverflow.com/a/8257295/463115) sul comportamento dello spazio SET – jeb

-2

lo faccio definendo una bandiera come TRUE, se necessario ...

rem /* sample code */ 
set VAR_SET= 
if <some condition> set VAR_SET=TRUE&set VAR=this data has spaces 

rem /* test for VAR_SET using 'if defined' */ 
if defined VAR_SET (
    rem /* do something with the other data in the variable %VAR% */ 
) 

rem /* clear the flag */ 
set VAR_SET= 
+1

Non avete risposto alla domanda - avete completamente perso il punto. – dbenham

Problemi correlati