Jest to bardzo niejasny przypadek narożny, w którym można rozważyć błąd w [definiowaniu wbudowanego testu ; jednak pasuje do zachowania rzeczywistego [pliku binarnego dostępnego w wielu systemach. O ile mogę powiedzieć, że dotyka tylko niektórych przypadkach i zmienną mającą wartość pasujący do [operatora jak (, !, =, -e, i tak dalej.
Pozwól mi wyjaśnić, dlaczego i jak obejść to w powłokach Bash i POSIX.
Wyjaśnienie:
Rozważ następujące:
x="("
[ "$x" = "(" ] && echo yes || echo no
Nie ma problemu; powyższe nie powoduje błędu, i wyniki yes. W ten sposób oczekujemy, że wszystko zadziała. Możesz zmienić ciąg porównania na, '1'jeśli chcesz, i wartość x, i będzie działać zgodnie z oczekiwaniami.
Zauważ, że rzeczywisty /usr/bin/[plik binarny zachowuje się w ten sam sposób. Jeśli uruchomisz np. Nie '/usr/bin/[' '(' = '(' ']'wystąpi błąd, ponieważ program może wykryć, że argumenty składają się z operacji porównywania jednego ciągu.
Błąd występuje, gdy my i z drugim wyrażeniem. Nie ma znaczenia, jakie jest drugie wyrażenie, o ile jest poprawne. Na przykład,
[ '1' = '1' ] && echo yes || echo no
wyprowadza yesi jest oczywiście prawidłowym wyrażeniem; ale jeśli połączymy te dwa,
[ "$x" = "(" -a '1' = '1' ] && echo yes || echo no
Bash odrzuca wyrażenie wtedy i tylko wtedy, gdy xjest (lub !.
Gdybyśmy mieli uruchomić powyższe za pomocą rzeczywistego [programu, tj
'/usr/bin/[' "$x" = "(" -a '1' = '1' ] && echo yes || echo no
błąd byłby zrozumiały: ponieważ powłoka dokonuje podstawień zmiennych, /usr/bin/[plik binarny odbiera tylko parametry ( = ( -a 1 = 1i zakończenie ], co zrozumiałe, nie analizuje, czy otwarte nawiasy rozpoczynają podwyrażenie, czy nie, z udziałem operacji i . Jasne, parsowanie go jako dwóch porównań ciągów jest możliwe, ale robienie tego zachłannie w ten sposób może powodować problemy po zastosowaniu do odpowiednich wyrażeń za pomocą nawiasów podwyrażeniowych.
Problem polega na tym, że [wbudowana powłoka zachowuje się w ten sam sposób, jakby zwiększała wartość xprzed sprawdzeniem wyrażenia.
(Te dwuznaczności i inne związane z rozszerzaniem zmiennych były głównym powodem, dla którego Bash zaimplementował i teraz zaleca używanie [[ ... ]]zamiast tego wyrażeń testowych).
Obejście jest trywialne i często występuje w skryptach używających starszych shpowłok. Często dodaje się „bezpieczny” znak xprzed ciągami (obie wartości są porównywane), aby zapewnić rozpoznanie wyrażenia jako porównania ciągów:
[ "x$x" = "x(" -a "x$y" = "x1" ]
[[ "$x" = '1' && "$y" = '1' ]]