Polecenie [ (nawias kwadratowy)

man [

[: [ argument... ]
    Obliczenie wyrażenia warunkowego.
    
    Jest to synonim dla wbudowanego polecenia "test", ale wymagający, by
    ostatnim argumentem był `]' pasujący do początkowego `['.

Informacja

Na ogólnym poziomie można przyjąc, że polecenie [ jest aliasem dla polecenia test. W bashu istnieje także polecenie [[, które jest ulepszoną wersją [.

Różnice pomiędzy poleceniami [, [[, a poleceniem test

Polecenie [ jest tym samym co wbudowane polecenie test i działa w sposób identyczny (jest zgodne z POSIX).

  • Jest przenośne pomiędzy różnymi powłokami, pozwala na sprawdzenie tylko pojedynczego warunku,
  • Nie ma możliwości sprawdzenia wielu warunków wewnątrz polecenia [], do robienia operacji AND i OR należy używać odpowiednio operatorów shell && i ||,
  • Polecenie [ nie pozwala na wykorzystanie negacji (!) - negacja musi być użyta poza nawiasami jak zwykła komenda shell,
  • Operator == i != są sprawdzeniami łancuchów tekstowych

Polecenie [ bardzo często jest mylone ze słowem kluczowym [[ (co w sumie nie powinno być zaskoczeniem dla nikogo ;-) …).

  • Polecenie [[ przez długi czas było specyficzne tylko dla powłoki bash (obecnie już wiele innych powłok ma je zaimplementowane np. KSH, ZSH),
  • Operator == i != pozwalają na użycie reguł matchowania („Pattern matching”),
  • Występuje operator =~ pozwalający na uzywanie wyrażeń regularnych,
  • Polecenie [[ pozwala na użycie nawiasów (()) i operatorów logicznych !, &&, || wewnątrz poecenia - zwiększając czytelność kodu

Przykłady użycia

W systemie plików mamy plik .bashrc wykorzystamy go do wykonania kilku ćwiczeń.

johny@ThinkPad:~$ ls -al1 .bashrc
-rw-r--r-- 1 johny johny 3771 gru 18 17:42 .bashrc

Informacja

Łączenie warunków

Niepoprawne uzycie polecenia [ (dosyć czesty błąd)

johny@ThinkPad:~$ bash <<\EOF
if [ -e .bashrc && -r .bashrc ] ; then
    echo "Istnieje plik .bashrc i masz prawa do jego odczytania";
fi
EOF
bash: line 1: [: missing `]'

Nowy sposób z [[

johny@ThinkPad:~$ bash <<\EOF
if [[ -e .bashrc && -r .bashrc ]] ; then
     echo "Istnieje plik .bashrc i masz prawa do jego odczytania";
fi
EOF
Istnieje plik .bashrc i masz prawa do jego odczytania

Stary sposób z [ (bardziej przenośny)

johny@ThinkPad:~$ bash <<\EOF
if [ -e .bashrc ] && [ -r .bashrc ] ; then
    echo "Istnieje plik .bashrc i masz prawa do jego odczytania";
fi
EOF
Istnieje plik .bashrc i masz prawa do jego odczytania

Nowy sposób z [[ (choć łączenie warunków jest „po staremu”)

johny@ThinkPad:~$ bash <<\EOF
if [[ -e .bashrc ]] && [[ -r .bashrc ]] ; then
    echo "Istnieje plik .bashrc i masz prawa do jego odczytania";
fi
EOF
Istnieje plik .bashrc i masz prawa do jego odczytania

Operatory porównywania łancuchów znakowych

Nowy operator [[ pozwala na porównywanie łancuchów znakowych w bardziej intuicyjny sposób.

Poniższy przykład pokazuje naiwne porównanie:

johny@ThinkPad:~$ bash <<\EOF
answer="yes"
if [ "$answer" = y -o "$answer" = yes ] ; then
    echo "Answer is YES"
fi
EOF
Answer is YES

Przykład z użyciem operatora [[ oraz =~ (operator wyrażeń regularnych znany z takich języków jak Perl) pozwala zrobić to samo znacznie mniejszym nakładem pracy.

Podpowiedź

Jezeli jestes już zaznajomiony z wyrażeniami regularnymi to można nawet „łapać” części dopasowań w zimenną ${BASH_REMATCH}. W poniższym przykładzie ${BASH_REMATCH[1]} będzie zawierał słowo „es”.

johny@ThinkPad:~$ bash <<\EOF
answer="yes"
if [[ $answer =~ ^y(es)?$ ]] ; then
    echo "Answer is YES"
fi
EOF
Answer is YES

Operator [[ pozwala w porównaniach na uzycie tzw. globbingu, poniższy przykład to ładnie demonstruje.

johny@ThinkPad:~$ bash <<\EOF
answer="yno"
if [[ $answer = y* ]] ; then
    echo "Answer is YES"
fi
EOF
Answer is YES
johny@ThinkPad:~$ bash <<\EOF
answer="YeS"
if [[ $answer = [yY][eE][sS] ]] ; then
    echo "Answer is YES"
fi
EOF
Answer is YES

Ostrzeżenie

Należy pamiętać, że rozszerzenia basha takie jak [[ najcześciej nie są kompatybilne z innymi shellami. Dlatego tak ważne jest by zadeklarować powłokę w której nasz skrypt ma być interpretowany - zobacz użycie shebang.