Jaki jest sens bash operatora zerowego „:”, dwukropka?

13

Jaki jest sens „zerowego” operatora w skrypcie BASH? Rozumiem, że jest używany jako symbol zastępczy po ifpoleceniu, gdy nie masz nic do powiedzenia, ale potrzebujesz polecenia, aby program mógł działać poprawnie. Ale jakie jest do tego ogólne zastosowanie? Kiedy go użyjesz? Kiedy warto go używać?

Justin
źródło
czytaj również Używanie
dwukropka jako bashowego
1
Powód, dla którego cytujesz, jest bardzo ważny. Dlaczego potrzebujesz więcej?
terdon

Odpowiedzi:

16

Czasami przydatne jest umożliwienie wystąpienia efektów ubocznych rozszerzenia parametrów.

Na przykład ustawienie wartości domyślnej

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
Glenn Jackman
źródło
2
Czy możesz wyjaśnić symbol po symbolu, jak działa druga linia?
Ruslan
Przeczytaj o rozszerzaniu :poleceń i parametrów w podręczniku bash.
glenn jackman
4
Aby zarysować, do czego odwołuje się @glennjackman, drugi wiersz wywołuje polecenie null: i ${name:="John Doe"}zostanie rozwinięty, powodując, że przypisanie nastąpi, ponieważ jest on odczytywany jako argument :. Bez: powłoka spróbuje uruchomić „John Doe” jako polecenie lub wartość, $namejeśli jest już ustawiona
imkendal
13

Możesz go również użyć do niekończących się pętli:

while : ; do 
   # ....
done
choroba
źródło
4
Ale być może while truejest bardziej czytelny, ponieważ (a) używa mniejszej interpunkcji i (b) jest bardziej podobny do języków pochodnych C.
wchargin
9

Możesz go użyć do utworzenia pliku bez uruchamiania programu:

: > /path/to/file

Jest to nieskończenie szybsze niż touch /path/to/file (ponieważ nie wymaga uruchamiania touchprogramu) i może być nieznacznie bardziej przenośne niż zwykłe

> /path/to/file

który wydaje się działać na wielu systemach. Podobnie można go użyć do sprawdzenia, czy masz dostęp do zapisu do pliku :

if { : >> /path/to/file;} 2> /dev/null
then
    echo "writeable"
else
    echo "write permission denied"
fi

chociaż można to również ogólnie zrobić bez :. Ostrzeżenia:

  • Nie sprawdza to, czy plik już istnieje. Jeśli nie, utworzy plik, jeśli będzie miał na to pozwolenie.
  • Jeśli plik nie istnieje, a skrypt nie ma uprawnień do jego utworzenia, pojawi się komunikat „Odmowa dostępu do zapisu”.

(Zobacz powiązane pytanie z przyczynami, dla których jest to bardziej wiarygodne niż if [ -w /path/to/file ].)

G-Man mówi „Przywróć Monikę”
źródło
5

Dawno temu, w Unixie V6 i Thompson Shell, :faktycznie był używany jako część gotoinstrukcji. Zgodnie z instrukcją pierwotnie pojawił się w wersji 3 Uniksa:

Cały plik poleceń jest przeszukiwany pod kątem linii rozpoczynającej się od: jako pierwszego niepustego znaku, po którym następuje jeden lub więcej spacji, a następnie etykieta. Jeśli taka linia zostanie znaleziona, goto przesuwa przesunięcie pliku poleceń do linii po etykiecie i kończy działanie. Powoduje to, że powłoka przechodzi do oznaczonej linii.

Obecnie bashjest używany jako operator no-op, powracający sukces. Rzeczywiście, jeśli spojrzysz na kod źródłowy , zobaczysz to truei :użyjesz tej samej funkcji int colon_builtin(), poniżej. Nie ma :wbudowanego polecenia, a /bin/truewłaściwie jest dość dużym poleceniem do tego, co robi.

:może być używany w dowolnym miejscu true, na przykład w command_that_can_fail || true, chociaż może to wprowadzić w błąd nie-ekspertów. Przeczytaj więcej na ten temat tutaj .

Sergiy Kolodyazhnyy
źródło
3

Możesz go użyć w pozytywnym teście ifpolecenia, gdy chcesz tylko zrobić coś po ujemnej stronie. Na przykład:

if [[ True == False ]]; then
    :
else
    echo "true <> flase"
fi

Bez :bash generowałby błąd składniowy.

To jest uproszczony przykład. Zasadniczo użyłbyś takiej techniki we wstępnym kodowaniu, gdy jeszcze nie napisałeś tego segmentu kodu i potrzebujesz czegoś, co nie generuje błędu.

WinEunuuchs2Unix
źródło
Dobra odpowiedź, chociaż na początku może się nie wydawać oczywiste, że jest to najbardziej przydatne w przypadku rzeczywistego polecenia w warunkach testu, na przykład if pgrep firefox >/dev/null ; then : ; else echo "Firefox not running"; fipokazywałoby błąd tylko wtedy, gdy Firefox nie był uruchomiony. Innymi słowy, gdy musisz coś zrobić tylko wtedy, gdy polecenie ma błąd. W pewnym sensie jest to równoważne pgrep firefox || echo "Firefox not running", choć bardziej czytelne i pozwala na większą liczbę poleceń
Sergiy Kolodyazhnyy
0

Właśnie użyłem go w skrypcie z poleceniami SSH, aby skrypt nie popełnił błędu.

W takim przypadku chcę sprawdzić, czy użytkownik może połączyć się z zestawem serwerów. Jeśli połączenie jest prawidłowe, zdalny host wyśle ​​echo OK. Jeśli połączenie się nie powiedzie, SSH odpowie błędem. Jednak chcę, aby mój skrypt zakończył działanie z wartością 0, a nie wartością polecenia SSH, jeśli się nie powiedzie. Zasadniczo wychwytuję błąd SSH, ORingując go ||poleceniem null :. Wygląda tak:

#!/bin/bash
for i in $(cat servers.txt); do
    echo -n "$i "; 
    ssh user@${i} 'echo OK' || :; 
done

W ten sposób otrzymuję dane wyjściowe z SSH, ale nie kod błędu:

....
swl06 ok
swl07 ok
swl08 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
swl09 ok
swl10 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
....
Michael J.
źródło