W jakim celu służy wbudowane dwukropek?

45

Włamałem się do wielu skryptów powłoki i czasami najprostsze rzeczy mnie zaskakują. Dzisiaj natknąłem się na skrypt, który szeroko wykorzystywał :wbudowane bash (dwukropek).

Documenation wydaje się dość proste:

: (a colon)  
     : [arguments]  

Nie rób nic poza rozszerzaniem argumentów i przeprowadzaniem przekierowań. Status powrotu wynosi zero.

Jednak wcześniej widziałem to tylko w demonstracjach ekspansji powłoki. Przypadek użycia w skrypcie, na który natknąłem się, w dużym stopniu wykorzystywał tę strukturę:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

W rzeczywistości były setki grepów, ale są one po prostu takie same. Nie ma żadnych przekierowań wejścia / wyjścia poza prostą strukturą powyżej. Żadne zwracane wartości nie są sprawdzane później w skrypcie.

Czytam to jako bezużyteczną konstrukcję, która mówi „albo nic nie rób”. Jaki cel może mieć zakończenie tych grepów „lub nic nie robić”? W jakim przypadku ten konstrukt spowodowałby inny wynik niż zwyczajne pominięcie || :wszystkich przypadków?

Caleb
źródło
10
Jednym z możliwych celów, jakie widzę, jest użycie :jako alternatywy dla true. Być może errexitjest ustawiony, a autor nie dba o status wyjścia niektórych poleceń.
jw013
połączona strona Stackoverflow jest IMO nieco bardziej obszerna (więc dobrze przeczytać zarówno tę stronę, jak i połączoną stronę).
Trevor Boyd Smith

Odpowiedzi:

29

Wygląda na :to, że zamiast twojego skryptu używane są litery true. Jeśli grepnie znajdzie dopasowania w pliku, zwróci niezerowy kod wyjścia; jak jw013 wspomina w komentarzu, jeśli errexitjest ustawiony, prawdopodobnie -ew linii shebang, skrypt zakończy działanie, jeśli którykolwiek z nich grepnie znajdzie pasującego elementu. Najwyraźniej nie tego chciał autor, więc dodał, || :aby status wyjścia tego konkretnego polecenia złożonego zawsze wynosił zero, jak w przypadku bardziej powszechnego (z mojego doświadczenia) || true/ || /bin/true.

Kevin
źródło
Duh. Było to w koncepcji skryptu kompilacji RPM i chociaż nie widziałem żadnego kodu wyjścia sprawdzającego wewnątrz skryptu, zapomniałem wziąć pod uwagę, że proces nadrzędny może obserwować.
Caleb
8
W takim przypadku nazwałbym to słabą praktyką skryptową. Jest to funkcjonalnie równoważne z używaniem truezamiast tego, ale cel semantyczny jest znacznie wyraźniejszy true. :jest bardziej odpowiedni, gdy pożądany jest wyraźny NOP.
jw013
Z mojego doświadczenia wynika, że ​​jest to powszechna praktyka w skryptach RPM. Prawdopodobnie nie powinno tak być, ale jesteśmy.
mattdm,
niektórzy puryści wolą :zamiast tego, trueponieważ :jest to bashwbudowany, gdzie jak truezwykle skompilowany plik binarny z większym narzutem. zwykle używam, trueponieważ kod jest bardziej czytelny (podobnie wolę używać sourcezamiast .).
Trevor Boyd Smith
36

:Wbudowane jest także przydatny z „przypisać wartości domyślne” ekspansji powłoki bash, gdzie ekspansja jest często wykorzystywane wyłącznie na efekt uboczny, a wartość rozszerzony jest wyrzucane:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}
Joni
źródło
2
Przybyłem tutaj, szukając tego, był zaskoczony, gdy zobaczyłem ten wzór w skrypcie, aby zadeklarować wartości domyślne.
ffledgling
21

Mogę wymyślić dwa miejsca, z których korzystałem :w przeszłości.

while :
do
     shell commands
     some exit condition
done

To jest pętla na zawsze.

function doSomethingStub {
    :
}

Włącz funkcję odgałęzienia, aby uzyskać prawidłowy przepływ sterowania na najwyższym poziomie.

Jedno użycie, które widziałem w dawnych czasach: Zamiast #!/bin/sh(lub cokolwiek) linii, zobaczyłbyś :linię. Niektóre starsze jądra Real Unix lub powłoki Real Unix użyłyby tego w znaczeniu „Jestem skryptem powłoki, uruchomiłem”. Jak pamiętam, było to właśnie wtedy, gdy csh robił inwazje jako wspólna interaktywna powłoka.

Bruce Ediger
źródło
@BruceEdiger: Czy masz odniesienie do linii „shecolon”?
l0b0
7
W końcu znalazłem odniesienie i wyjaśnienie „: na początku skryptu”: faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger
1
zachowanie na początku :jest bardzo dziwne. odkryłem, że rzeczywiście powoduje to uruchomienie skryptu sh. gdzie tak jak podczas uruchamiania skryptu bez shebang ... próbuje uruchomić skrypt z jakąkolwiek uruchomioną powłoką (więc jeśli bashgo uruchomisz , spróbuje uruchomić go tak bash, jakbyś cshto zrobił csh).
Trevor Boyd Smith
19

:Wbudowaną był już w Thompson skorupy - to udokumentowane na Unix V6 w roku 1975. W Thompson skorupkach, :wskazany etykietę gotopolecenia. Jeśli nigdy nie próbowałeś zadzwonić gotona linię zaczynającą się od , ta linia była faktycznie komentarzem.

Bourne shell , przodek muszli Bourne'a / POSIX, jakie znamy, nigdy nie miał gotoo tym nie wiem, ale zachowane :jako no-op polecenie (to był już obecny w Unix V7 ).

Gilles „SO- przestań być zły”
źródło
Punkt na pouczające tło historyczne.
Tony Barganski
12

Wykopałem stare odniesienie: „The UNIX Programming Environment” (c) 1984 autorstwa Kernighana i Pike'a.

Strona 147 (Programowanie powłoki) mówi:

„:” jest wbudowanym poleceniem powłoki, które dokonuje oceny argumentów i zwraca „prawda”. Zamiast tego [odnosząc się do przykładu skryptu], moglibyśmy użyć wartości true , która jedynie zwraca prawdziwy status wyjścia. (Istnieje również polecenie fałszywe .) Ale „:” jest bardziej wydajne niż prawdziwe, ponieważ nie wykonuje polecenia z systemu plików . [Kursywa / wyróżnienie jest moje.]

fracjackmac
źródło
2
Oczywiście truejest teraz także powłoką wbudowaną w wiele systemów.
tripleee
8

Wydaje mi się, że pamiętam, że wczesne wersje powłoki nie miały składni komentarzy. Linia zaczynająca się od :(która prawdopodobnie byłaby rzeczywistym plikiem wykonywalnym, podobnym do /bin/true) byłaby najlepszą alternatywą.

Oto strona podręcznika dla starożytnej powłoki Thompsona (bez relacji); nie ma wzmianki o żadnej składni komentarza.

Keith Thompson
źródło
4
Pochodzenie :było w rzeczywistości wskaźnikiem etykiety dla gotopolecenia, w jakiejś starożytnej powłoce (nie wiem która). Etykieta : somethingrzeczywiście mogłaby zostać użyta jako komentarz, gdyby nie było pasującego goto. Praktyka utknęła nawet po gotozniknięciu.
Gilles „SO- przestań być zły”
8

„:” jest przydatne do debugowania.

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

Działa normalnie, funkcja debugowania nigdy nie jest wykonywana, więc po prostu przesuń się o krok dalej (zmienne i symbole wieloznaczne są rozwijane). Jeśli wymagane jest bardziej szczegółowe debugowanie, usuń noop ze zmiennej, a funkcja debugowania zostanie wywołana z dowolnymi wymaganymi argumentami.

Innym przydatnym zastosowaniem jest komentarz blokowy, który jest brakującą cechą składni powłoki.

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
Colin
źródło