2011-11-24 7 views
6

Nazwy zmiennych środowiskowych zdefiniowanych przez użytkownika systemu Windows mogą zawierać dowolny znak z wyjątkiem =.Jaka składnia sprawdzi, czy zdefiniowana jest nazwa zmiennej zawierająca spacje?

Znaki specjalne można wstawiać po nich. Prostszą metodą jest po prostu ujęcie całego wyrażenia SET w cudzysłowach. Na przykład:

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

Oba wyrażenia powyżej dają taki sam wynik. Nazwa zmiennej jest A weird & "complex" variable a wartość My value

jeśli określona konstrukcja służy do sprawdzenia, czy zmienna została zdefiniowana. Cytaty nie działają dla tego testu, znaki specjalne w nazwie (łącznie z cudzysłowami) muszą zostać usunięte.

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

Powyższy test ucieczki działa dobrze. Przytoczony test nie działa

Ale jak mogę sprawdzić, czy istnieje zmienna zawierająca spacje?

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

Wydaje się, że powyższe powinny działać, ale tak nie jest!

Poszukuję odpowiedzi, która NIE obejmuje rozszerzania zmiennej za pomocą% A B% lub! A B!

Odpowiedz

5

Interesujące pytanie (uwielbiam te podstawowe pytania dotyczące składni).

Oczywiście wiesz, jak to sprawdzić z opóźnionym rozszerzeniem, a także pracuje z parametrami FOR.

@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 

W moim opionion, w przykładzie escape2 parser najpierw podzielić linię na tokeny w ten sposób:
<if> <defined> <AAA BBB> <echo .... Ale w czasie wykonywania tego jeśli określona to ponowne skanowanie <AAA BBB> tokena więc otrzymuje tylko AAA.
Nie można wstrzyknąć drugą ucieczkę jak AAA^^^ BBB ponieważ tylko wyszukuje zmiennej o nazwie AAA^

nie widzę rozwiązania bez opóźniania/FOR, gdyż wyciek większej ilości przestrzeni zawsze kończy się niepowodzeniem.

Edycja: może być rozwiązany SET <varname>
Roztwór ijprest wykorzystuje polecenie na TEST zmiennej, bez konieczności ucieczki VARNAME.
Ale pokazuje także interesujące zachowanie ze spacjami w środku i na końcu nazwy zmiennej.

Wydaje się według poniższych zasad:
SET varname wyszukiwania dla wszystkich zmiennych rozpoczynających się nazwa_zmiennej, ale najpierw usuwa wszystkie znaki po ostatnim znaku kosmicznego nazwa_zmiennej i usuwa wszystkie spacje.
Nie można więc wyszukiwać zmiennych rozpoczynając od spacji (ale utworzenie takiej nazwy jest nieco trudniejsze).

To samo zachowanie jest również aktywne, jeśli nazwa zmiennej zmiennej jest ujęta w cudzysłów, ale istnieje jeszcze jedna reguła.
Najpierw usuń wszystkie znaki po ostatnim cytacie, jeśli są co najmniej dwie cytaty. Użyj tekstu wewnątrz cytatów i użyj znaku "spacja".

Próbka.

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

FOR /! Opóźnić! rozwiązanie nie było oczywiste, kiedy potrzebowałem snu. Myślałem o tym, kiedy się obudziłem, ale już napisałeś znakomitą odpowiedź! :) – dbenham

+0

Twoja * analiza escape2 * jest bardzo interesująca. Jeszcze jedna okazja, aby wprowadzić komentarz do oświadczenia – dbenham

0

Drugi sposób polega na przeniesieniu go do innej zmiennej (bez przestrzeni) oraz testu tym. Zobacz tutaj:

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

Oczywiście, że działa, ale ostatni wymóg mojego pierwotnego pytania stwierdził, że szukałem odpowiedzi, która NIE używała% A B% lub! A B !. (BTW, przypisywanie! A B! Jest znacznie bezpieczniejsze.Zadanie% A B% może się nie udać w zależności od zawartości) – dbenham

3

Uwielbiam też tego rodzaju pytanie! :)

Oto kolejna z możliwych rozwiązań wymyśliłem ... używając samo urządzenie do testowania istnienia, a przy użyciu wynik 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 

Zauważ, że to działa tylko jeśli zmienne są wyjątkowy w tym sensie, że żadna nazwa zmiennej nie jest prefiksem innego. W przeciwnym razie ryzykujesz fałszywe alarmy, ponieważ domyślnym ustawieniem SET jest pokazywanie wszystkich zmiennych rozpoczynających się od przekazanego parametru. Czy to może być przypadek, można filtrować wyniki z 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) 

Również pojedynczy przestrzeń spływu po nazwie zmiennej wydaje się być konieczne. Bez tego SET często błędnie analizuje dane wejściowe. Dziwnie, jeśli dodasz dodatkowe spacje między "2> nul" i "& &" w przypadku # 3, przestanie działać (chyba że usuniesz spację przed "> nul") ... dziwne.

+0

+1 Dobre rozwiązanie z dodatkiem FINDSTR. Myślałem o teście SET i go odrzuciłem, ale nie pomyślałem o dodaniu FINDSTR. Wciąż wolę rozwiązanie firmy jeb, ponieważ nie wymaga ono użycia rurek ani zewnętrznego polecenia, więc jest szybsze. – dbenham

+0

Bardzo interesujące odkrycie o dodatkowej przestrzeni wymagało innej zmiennej zaczynającej się od "a". Cytaty nie są potrzebne. 'ustaw b' nie działa. 'set a b ' działa. 'set a b ' zawiedzie! @jeb - jakiekolwiek pomysły, co tu się dzieje? – dbenham

+0

Dodaję komentarz do mojej [odpowiedź] (http://stackoverflow.com/a/8257295/463115) o zachowaniu przestrzeni SET – jeb

-2

robię to poprzez zdefiniowanie flagę jako PRAWDA, jeśli potrzebny ...

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

Nie odpowiedziałeś na pytanie - całkowicie pomijasz punkt. – dbenham