Dlaczego warto stosować podwójne cudzysłowy w teście [[]]?


23

Powiedzmy, że mamy 2 liczby całkowite w skrypcie bash:

value1=5
value2=3

Dlaczego więc musimy używać podwójnych cudzysłowów w przypadku testu? Na przykład:

if [[ "$value1" -eq "$value2" ]]

Dlaczego nie skorzystać z poniższych?

if [[ $value1 -eq $value2 ]]

Dla mnie podwójne cytaty nie mają żadnego sensu.


5
Cytowanie w powłoce ma niewiele wspólnego z łańcuchami (jak w typach danych). Naprawdę chodzi o to, by powłoka nie wykonywała podziału słów (i innych rodzajów rozszerzeń.)
filbranden

13
Podczas gdy, jak zauważył terdon, nie jest konieczne zbyt częste cytowanie zmiennych w tym konkretnym konstrukcie (i, oczywiście, z wartościami jednego słowa w dowolnym miejscu), chciałbym udzielić porady, aby zawsze cytować twoje zmienne. Czy naprawdę wiesz, w jakich kontekstach możesz pozostawić zmienne bez cudzysłowu? Powodem zacytować w ogóle, nawet jeśli nie jest to konieczne ze 5i 3jest łatwość konserwacji. Wartości mogą ulec zmianie później, a powstałe błędy mogą nie być oczywiste.
Peter - Przywróć Monikę

2
@sudodus Nie sądzę, że to prawda [[ ]], tylko dla [ ].
Benjamin W.

1
Masz rację, @BenjaminW. Podział słów to nie jedyny przypadek, dla którego warto używać podwójnych cudzysłowów dla zmiennych. Jest tak również w przypadku, gdy zmienna jest pusta. To spowoduje, że instrukcja w [] się nie powiedzie (na przykład [2 -eq] z błędem, ale [[]] nie jest podatny na atak (jak w przypadku dzielenia słów).
sudodus

2
@marcelm, Bash, ksh i Zsh mają zmienne całkowite, w [[ ]]których również wymuszają operandy -eqna liczby całkowite.
ilkkachu

Odpowiedzi:


7

Podział słów.

Ten przykład jest bardzo nieprawdopodobny, ale możliwy , więc jeśli chcesz kodować defensywnie, zakryj swoje utwory cytatami:

$ set -x
$ value1=5
+ value1=5
$ value2=3
+ value2=3
$ [ $value1 -eq $value2 ]
+ '[' 5 -eq 3 ']'

OK, jak dotąd wszystko dobrze. Wrzućmy klucz do kół zębatych:

$ IFS=456
+ IFS=456
$ [ $value1 -eq $value2 ]
+ '[' '' -eq 3 ']'
bash: [: : integer expression expected

Ups

$ [ "$value1" -eq "$value2" ]
+ '[' 5 -eq 3 ']'

Ahh


2
Ale OP używa podwójnych nawiasów, więc nie ma podziału słów.
user000001

5
Tak, to nie jest tak naprawdę istotne dla [[ ]]konstrukcji bash .
terdon

1
Co? [ $value1 -eq $value2 ]z pustym value1byłoby '[' -eq 3 ']'bez ''po lewej stronie.
Charles Duffy

Byłem też zaskoczony, ale są dowody.
glenn jackman

1
Ta odpowiedź nie dotyczy bezpośrednio pytania. Dziwię się, że został zaakceptowany. Ustawienie jako wiki społeczności.
glenn jackman

35

Tak naprawdę nie potrzebujesz tutaj cytatów. Jest to jeden z nielicznych przypadków, w których można bezpiecznie używać zmiennej niecytowanej. Możesz to potwierdzić za pomocą set -x:

$ var1=""
$ var2="3"
$ set -x
$ if [[ $var1 -eq $var2 ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!
$ if [[ "$var1" -eq "$var2" ]]; then echo "match!"; else echo "no match!"; fi
+ [[ '' -eq 3 ]]
+ echo 'no match!'
no match!

Jak widać powyżej, cytowane i niecytowane wersje testu są rozwiązywane dokładnie tak samo przez bash. To samo powinno być prawdą zshi, jak sądzę, każdą inną powłoką, która obsługuje [[ ]]operatora.

Pamiętaj, że nie jest tak w przypadku bardziej przenośnych [ ]:

$ if [ $var1 -eq $var2 ]; then echo "match!"; else echo "no match!"; fi
+ '[' -eq 3 ']'
sh: [: -eq: unary operator expected
+ echo 'no match!'
no match!

[ ]Konstrukt, w przeciwieństwie do [[ ]]jednego, nie wymaga cytowania.


Kilka przydatnych linków, aby dowiedzieć się więcej o tym, kiedy i dlaczego wymagane jest cytowanie:


W tym przypadku ze zmiennymi całkowitymi lepiej byłoby zadeklarować je jako takie. declare -i var1=jest 0oceniany.
Freddy

4
Zauważ, że -eqjest to porównanie arytmetyczne , więc możesz nawet pominąć $(w [[ .. ]]) i pisać [[ a -eq b ]]. Przy porównywaniu ciągów potrzebujesz $oczywiście, więc[[ $a = $b ]]
ilkkachu

2
@ user000001 dobry punkt. Chociaż oczywiście jest bardzo możliwe, że chcesz je rozbudować. Na przykład, chciałbym się spodziewać, że jest to mecz: var1="afoob"; var2="a*b"; [[ $var1 = $var2 ]] && echo match. Jeśli chcesz używać znaków globu bez działania jako glob w kontekście globowania (takim jak [[ ]]), musisz zacytować, tak.
terdon

3
@ilkkachu, to mnie zaskakuje. Myślałem, że zmienne „gołe” będą brane pod uwagę tylko w indeksie tablicy lub ((...))lub $((...). Wygląda na to, że działa, ale (stary zrzędliwy mężczyzna, włącz) Nie podoba mi się to.
glenn jackman

1
@glennjackman, cóż, przepraszam, że powiedziałem ci to, ale tak, operandy -eqi przyjaciele wewnątrz [[ ]]są również kontekstami arytmetycznymi. :) (Powiązane: Automatyczne rozszerzanie zmiennych wewnątrz polecenia bash [[]] )
ilkkachu

17

Mimo że podwójne cudzysłowy nie są konieczne, powody ich zastosowania to:

  • Dobra praktyka / nawyk: w tym przypadku nie są one konieczne, ale ogólnie podwójne cudzysłowy mają na celu uniknięcie niezamierzonego podziału słów.
  • Ponieważ value1i value2są zmienne i możesz nie wiedzieć, co one zawierają. W przeciwnym razie równie dobrze możesz zapytać: „Po co zawracać sobie głowę zmiennymi zamiast sprawdzać if [[ 5 -eq 3 ]]? Albo pójść dalej, po ifco w ogóle zawracać sobie głowę, skoro już wiesz, że 5 nie jest równe 3? Często lepiej jest być defensywnym. (To prawda dzielenie słów nie nastąpi [[, ale przypadki, w których dzielenie słów się nie zdarza, są rzadkie. Ponownie zobacz pierwszy punkt).

1

Nie bezpośrednio związane z twoim pytaniem, ale używam

if ((wartość $ 1 == wartość $ 2)); następnie

kiedy porównuję liczby, ale tam też nie musicie używać cudzysłowów.


2
if (( value1 == value2 )); then. W kontekście arytmetycznym nawet nie potrzebujesz $. To pytanie wydaje się jednak koncentrować na zmiennych używanych w [[ ... ]]testach.
Kusalananda

1
Wiem. Ale szczerze mówiąc, nie używam tej funkcji, ponieważ chcę, aby moje nazwy zmiennych były spójne, a zatem cały czas używam $ jako prefiksu.
framp

1

Masz absolutną rację!

Cytowanie w podwójnych nawiasach kwadratowych nie ma żadnego sensu, przynajmniej w tym przypadku.

Ale ponieważ codziennie używam podwójnych cudzysłowów - szczególnie w przypadku wyrażeń w nawiasach kwadratowych, przekazywania argumentów do funkcji i skryptów, a także czasami przypisywania zmiennych (co jest całkowicie bezużyteczne w przypadku prostych delarkacji) - wydaje mi się, że niektórzy ludzie, przynajmniej tak robię, instynktownie pisz podwójne cudzysłowy wokół zmiennych .

Podwójne cytowanie może dać poczucie soczystości. To jest jak powrót do domu, gdzie są podwójne cytaty. - D. Kummer

Korzyść z konsekwentnego i zrozumiałego wykonywania podwójnych cudzysłowów - ale tylko wtedy, gdy ma to sens - polega na tym, że nowicjusze w bash mogą nauczyć się pisać bardziej stabilne skrypty . Podkreśla to również fakt, że sztuka przetwarzania danych za pomocą bash polega bardziej na oddzielaniu strumieni danych (w tym zmiennych) za pomocą separatorów pól i przepuszczaniu ich przez filtry . Gdy tylko oddzielisz fragmenty danych od strumienia, trzymaj je razem z podwójnymi cudzysłowami!

Kolejną korzyścią może być lepsza czytelność skryptów bash z podwójnie napisanymi ciągami w edytorze podświetlania kodu .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.