Zobacz BashFAQ # 105 re: Whyset -e jest uważany za znacznie bardziej podatny na błędy niż ręczna obsługa błędów. (Jeśli się spieszysz, pomiń analogię u góry dotyczącą poniższych ćwiczeń).
Charles Duffy
Odpowiedzi:
70
W zasadzie pobiera wszelkie argumenty wiersza poleceń przekazane do entrypoint.shi wykonuje je jako polecenie. Intencją jest w zasadzie „Zrób wszystko w tym skrypcie .sh, a następnie w tej samej powłoce uruchom polecenie, które użytkownik podaje w wierszu poleceń”.
Zauważ również, że exec "$@"spowoduje to zastąpienie aktualnie działającego procesu nowym procesem utworzonym dla przekazanych argumentów. Ważne dla sygnalizacji Docker: stackoverflow.com/a/32261019/99717
Hawkeye Parker
34
set -eustawia opcję powłoki na natychmiastowe zakończenie, jeśli dowolne uruchamiane polecenie kończy działanie z niezerowym kodem zakończenia. Skrypt zwróci kod zakończenia polecenia, które zakończyło się niepowodzeniem. Ze strony podręcznika bash:
ustaw -e:
Zakończ natychmiast, jeśli potok (który może składać się z pojedynczego prostego polecenia), lista lub polecenie złożone (zobacz powyżej GRAMATURA POWŁOKI), kończy działanie z niezerowym statusem. Powłoka nie kończy działania, jeśli polecenie, które się nie powiedzie, jest częścią listy poleceń występujących bezpośrednio po słowie kluczowym while lub until, częścią testu następującą po zastrzeżonych słowach if lub elif, częścią dowolnego polecenia wykonanego w a && lub || list z wyjątkiem polecenia następującego po ostatnim && lub ||, dowolnym poleceniu w potoku oprócz ostatniego lub jeśli wartość zwracana polecenia jest odwracana za pomocą!. Jeśli polecenie złożone inne niż podpowłoka zwraca stan niezerowy, ponieważ polecenie zakończyło się niepowodzeniem, podczas gdy -e było ignorowane, powłoka nie kończy działania. Pułapka na ERR, jeśli jest ustawiona, jest wykonywana przed zakończeniem działania powłoki.
Jeśli polecenie złożone lub funkcja powłoki są wykonywane w kontekście, w którym -e jest ignorowane, ustawienie -e nie będzie miało wpływu na żadne z poleceń wykonywanych w poleceniu złożonym lub treści funkcji, nawet jeśli -e jest ustawione, a polecenie zwraca wartość stan awarii. Jeśli polecenie złożone lub funkcja powłoki ustawia wartość -e podczas wykonywania w kontekście, w którym -e jest ignorowane, to ustawienie nie będzie miało żadnego efektu, dopóki polecenie złożone lub polecenie zawierające wywołanie funkcji nie zostanie zakończone.
exec "$@"jest zwykle używany do przejścia przez punkt wejścia, a następnie uruchamia polecenie docker. Zastąpi bieżącą uruchomioną powłokę poleceniem, na które "$@"wskazuje. Domyślnie ta zmienna wskazuje argumenty wiersza poleceń.
Jeśli masz obraz z punktem wejścia wskazującym na entrypoint.sh i uruchamiasz kontener jako docker run my_image server start, to przełoży się to na działanie entrypoint.sh server startw kontenerze. W linii exec entrypoint.sh, powłoka działająca jako pid 1 zastąpi się poleceniem server start.
Ma to kluczowe znaczenie dla obsługi sygnału. Bez użycia exec, server startw powyższym przykładzie działałby jako inny pid, a po zakończeniu wróciłbyś do skryptu powłoki. W przypadku powłoki w pid 1, SIGTERM będzie domyślnie ignorowany. Oznacza to, że wdzięczny sygnał stop, który docker stopwysyła do twojego kontenera, nigdy nie zostałby odebrany przez serverproces. Po 10 sekundach (domyślnie) docker stopzrezygnowałby z wdzięcznego zamknięcia i wysłał SIGKILL, który zmusi twoją aplikację do wyjścia, ale z potencjalną utratą danych lub zamkniętymi połączeniami sieciowymi, które twórcy aplikacji mogliby zakodować, gdyby otrzymali sygnał. Oznacza to również, że zatrzymanie pojemnika zawsze zajmie 10 sekund.
Zauważ, że za pomocą poleceń powłoki, takich jak shifti set --, możesz zmienić wartość "$@". Np. Tutaj jest krótka część skryptu, który usuwa /bin/sh -c "..."polecenie z polecenia, które może się pojawić, jeśli użyjesz składni powłoki Dockera dla CMD:
Zobacz specyfikację POSIXtest , która oznacza -aprzestarzałe. [ "$#" -gt 1 ] && [ "$1" = /bin/sh ]jest poprawnym zamiennikiem (nie ma potrzeby x"$1"hakowania, gdy używasz tylko nieaktualnej składni).
@CharlesDuffy dzięki za wskazówkę na temat przestarzałej opcji, jestem pewien, że znowu popełnię ten błąd, stare nawyki umierają. Wydaje evalmi się, że nadal chcę, aby odzwierciedlało to zachowanie /bin/sh -cna strunie, ale daj mi znać, jeśli czegoś brakuje.
BMitch
30
set -e - wyjdź ze skryptu, jeśli jakiekolwiek polecenie nie powiedzie się (wartość niezerowa)
exec "$@"- przekieruje zmienne wejściowe, zobacz więcej tutaj
set -e
jest uważany za znacznie bardziej podatny na błędy niż ręczna obsługa błędów. (Jeśli się spieszysz, pomiń analogię u góry dotyczącą poniższych ćwiczeń).Odpowiedzi:
W zasadzie pobiera wszelkie argumenty wiersza poleceń przekazane do
entrypoint.sh
i wykonuje je jako polecenie. Intencją jest w zasadzie „Zrób wszystko w tym skrypcie .sh, a następnie w tej samej powłoce uruchom polecenie, które użytkownik podaje w wierszu poleceń”.Widzieć:
źródło
exec "$@"
spowoduje to zastąpienie aktualnie działającego procesu nowym procesem utworzonym dla przekazanych argumentów. Ważne dla sygnalizacji Docker: stackoverflow.com/a/32261019/99717set -e
ustawia opcję powłoki na natychmiastowe zakończenie, jeśli dowolne uruchamiane polecenie kończy działanie z niezerowym kodem zakończenia. Skrypt zwróci kod zakończenia polecenia, które zakończyło się niepowodzeniem. Ze strony podręcznika bash:exec "$@"
jest zwykle używany do przejścia przez punkt wejścia, a następnie uruchamia polecenie docker. Zastąpi bieżącą uruchomioną powłokę poleceniem, na które"$@"
wskazuje. Domyślnie ta zmienna wskazuje argumenty wiersza poleceń.Jeśli masz obraz z punktem wejścia wskazującym na entrypoint.sh i uruchamiasz kontener jako
docker run my_image server start
, to przełoży się to na działanieentrypoint.sh server start
w kontenerze. W linii execentrypoint.sh
, powłoka działająca jako pid 1 zastąpi się poleceniemserver start
.Ma to kluczowe znaczenie dla obsługi sygnału. Bez użycia
exec
,server start
w powyższym przykładzie działałby jako inny pid, a po zakończeniu wróciłbyś do skryptu powłoki. W przypadku powłoki w pid 1, SIGTERM będzie domyślnie ignorowany. Oznacza to, że wdzięczny sygnał stop, którydocker stop
wysyła do twojego kontenera, nigdy nie zostałby odebrany przezserver
proces. Po 10 sekundach (domyślnie)docker stop
zrezygnowałby z wdzięcznego zamknięcia i wysłał SIGKILL, który zmusi twoją aplikację do wyjścia, ale z potencjalną utratą danych lub zamkniętymi połączeniami sieciowymi, które twórcy aplikacji mogliby zakodować, gdyby otrzymali sygnał. Oznacza to również, że zatrzymanie pojemnika zawsze zajmie 10 sekund.Zauważ, że za pomocą poleceń powłoki, takich jak
shift
iset --
, możesz zmienić wartość"$@"
. Np. Tutaj jest krótka część skryptu, który usuwa/bin/sh -c "..."
polecenie z polecenia, które może się pojawić, jeśli użyjesz składni powłoki Dockera dlaCMD
:# convert `/bin/sh -c "server start"` to `server start` if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then shift 2 eval "set -- $1" fi .... exec "$@"
źródło
test
, która oznacza-a
przestarzałe.[ "$#" -gt 1 ] && [ "$1" = /bin/sh ]
jest poprawnym zamiennikiem (nie ma potrzebyx"$1"
hakowania, gdy używasz tylko nieaktualnej składni).shift 2; set -- $1
nie jest tym samym, co sposób, w jakieval
przeanalizuje ciąg. Zastanów się/bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'
, czy chcesz mieć konkretny przypadek testowy i zobacz, że Bash nie analizuje cudzysłowów podczas konwersji ciągu znaków na argumenty .eval
mi się, że nadal chcę, aby odzwierciedlało to zachowanie/bin/sh -c
na strunie, ale daj mi znać, jeśli czegoś brakuje.set -e
- wyjdź ze skryptu, jeśli jakiekolwiek polecenie nie powiedzie się (wartość niezerowa)exec "$@"
- przekieruje zmienne wejściowe, zobacz więcej tutajźródło
exec
z pewnością ma tryb użycia, w którym wykonuje przekierowania, ale to nie jest ten tryb.