pozyskiwanie skryptu Bash - Return on Error, zamiast Exit?

17

Korzystam ze skryptu bash w terminalu , więc wychodzę z błędu

set -o errexit

zabija mój terminal, co jest niesamowicie denerwujące, ponieważ muszę zamknąć terminal, otworzyć inny i zresetować niektóre zmienne.

Do tej pory za pomocą

command || return

wiersze w skrypcie robią dokładnie to, co chcę

set -o errexit

robić ... Ale chcę, żeby zrobiono to dla całego skryptu; nie tylko jedna linia / polecenie

Mam plik pełen poleceń do konfigurowania witryny i wolałbym nie wykonywać poleceń || powrót

dla każdej linii w pliku

Czy istnieje inna opcja zestawu lub coś, co po prostu „powróci” zamiast wychodzić z terminala?

- Dla jasności chciałbym zabić skrypt i pozostawić terminal w tym samym stanie, co naciśnięcie klawiszy Ctrl + C, aby zabić usługę uruchomioną w terminalu. command || returnrobi to. Ale nie chcę przyczepiać się || returndo każdej linii w pliku. Więc szukam czegoś podobnego set -o errexit, co nie spowoduje zamknięcia terminala

--- Uwaga: Tworzenie głupiego skryptu zawierającego dwie linie (super.sh):

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

I umieszczenie set -o errexitna górze create.sh,

działa dokładnie tak, jak tego oczekuję. Jednak naprawdę głupie jest tworzenie pliku zawierającego dwie linie, aby wywołać inny skrypt bash, zamiast wywoływać go z terminala. Uhghhh

oto kilka przykładów:

w super.sh

#!/bin/bash

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

w create.sh

#!/bin/bash
set -o errexit
#line below this is a line that fails and will cause the script to stop and return to the terminal as expected 
sed "s/@@SITE_NAME@@/$dirname" 
~/Desktop/site_builder/template_files/base.html > ~/Desktop/$dirname/templates/base.html # a line with a stupid error

w terminalu:

 $ bash super.sh

wynik zgodny z oczekiwaniami:

my-mac$

To działa. Co za irytujące rozwiązanie.

I chce , najlepiej, aby wykonać to, co znajduje się w głupiej pliku super.sh z terminala, a nie pliku super.sh: D, bez konieczności wyłączania terminala na mnie. Oto, co dzieje się z tym, co próbuję zrobić:

polecenie terminala:

my-mac$ source $create_path blah

w create.sh nadal mam set -o errexit

Oto wynik na terminalu

    sed: 1: "s/@@SITE_NAME@@/blah": unterminated substitute in regular expression
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

A następnie terminal jest zamrożony. Ctrl + C nie działa, podobnie jak Ctrl + D

Jeśli zamiast tego set -o errexit, jeśli po prostu używam command || returninstrukcji wszędzie w pliku create.sh, to dostaję dokładnie to, czego chcę, wykonując wiersze w supser.sh bezpośrednio na terminalu (zamiast wywoływać super.sh z terminalu). Ale to też nie jest praktyczne rozwiązanie.

Uwaga: Podobała mi się odpowiedź @terdona dotycząca po prostu odradzania powłoki potomnej, więc skończyłem po prostu odradzaniem powłoki podrzędnej za pomocą skryptu zamiast terminala, jak pokazał w swojej odpowiedzi za pomocą nawiasów klamrowych ( )wokół całego skryptu. Jego odpowiedź też działa.


źródło
Czy robisz to w skrypcie czy ręcznie?
terdon
Dzwonię do pliku ze źródłem w terminalu. Jak w: source $file_path argumentSkrypt jest wykonywany w tej samej powłoce, z której go sourcecommand || return
OK i gdzie jest ustawiony zestaw? Czy to w skrypcie źródłowym, czy uruchamiasz go ręcznie? O wiele łatwiej byłoby odpowiedzieć, gdybyś mógł dodać prosty przykład, który możemy skopiować i wypróbować. Mam pomysł, ale potrzebuję sposobu przetestowania, aby upewnić się, że działa.
terdon
Dodałem notatkę do oryginalnego postu, która może w tym pomóc. Ale zrobię też, jak zasugerowałeś.

Odpowiedzi:

5

Po prostu źródło pliku z bezpiecznym:

source the-source-file || true

... wtedy ogólne polecenie nie zawiedzie, nawet jeśli sourcenie.

Jeff Schaller
źródło
Właściwie to myślałem, że tego właśnie chciałem, ale okazuje się, że mój terminal był po prostu powolny ... Naprawdę chcę wrócić do terminala po błędzie (co oznacza, że ​​zatrzymam cały skrypt na ścieżce) ... z jakiegokolwiek powodu, source file || true nie robi tego, source file || return
Pozyskanie pliku nie powoduje powrotu do powłoki?
Jeff Schaller
oto, co jest w moim terminalu: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || truepo prostu wykonuje następną część skryptu po awarii, więc zwraca wartość zamiast prawdy. Jedyne, co zadziałało, to command || returninstrukcje w rzeczywistym pliku dla wszystkich poleceń, co jest głupie. Nie wiem, czy rzucenie tego wszystkiego w funkcję, a następnie wywołanie function || returnna końcu pliku również by się przydało.
Cóż, jeśli wyraźnie || returnwydasz polecenie, które się nie powiedzie, tak, ono zwróci. Myślałem, że próbujemy powstrzymać twoją główną / rodzicielską powłokę przed wyjściem?
Jeff Schaller
Tak, chcę, aby terminal faktycznie nie wychodził. Ponieważ nie chcę wychodzić z terminalu. Chcę wyjść ze skryptu. Zwracanie poszczególnych poleceń w skrypcie powoduje wyjście ze skryptu i pozostawia mój terminal w tym samym stanie, co naciśnięcie Ctrl + C, aby zabić proces, taki jak uruchomienie serwera z terminala. Chcę uniknąć pisania polecenia || powrót do każdej linii w pliku: D
3

Jest to jedyna rzecz, która działa dla tego, co musiałem osiągnąć (stworzenie środowiska wirtualnego, następnie aktywacja go, a następnie instalacja wymagań ze skryptu bash):

spawnuje powłokę podrzędną / potomną ze skryptu, jak w:

stupid_file.sh

(
set -o errexit
#bunch of commands
#one line fails
)

uruchom plik stupid_file używając:

source stupid_file.sh <file arguments here> || true

KONIEC.

** bierze ukłon **

(podziękowania dla Jeffa i Terdona)


źródło
1
To tak naprawdę nie różni się niczym od wykonania skryptu zamiast jego pozyskiwania.
chepner
@chepner hmmm. Chłodny. Będę musiał spróbować zadzwonić bash $create_path blahi sprawdzić, czy nadal się kończy, wykonuje tę samą procedurę i nadal poprawnie instaluje elementy w moim środowisku wirtualnym. Nie ma czasu.
Zaoszczędzę ci czasu: nie zrobi tego (jeśli przez „instaluje rzeczy” masz na myśli ustawienie zmiennych środowiskowych w bieżącej powłoce), i to też nie będzie (...), ponieważ wszystkie przypisania w nawiasach wpływają tylko na tę podpowłokę. foo=3; (foo=5); echo "$foo"
wypisze
@chepner nie do końca. Nie mogę dzwonić source filez terminala i oczekuję takich samych rezultatów. Ponieważ to nigdy nie działało. Jedyne czasy, kiedy otrzymuję te same wyniki, to jawne utworzenie sub-powłoki, czy to przez terminal, czy ze skryptu. Mogę jednak użyć bashzamiast sourcedo wykonania skryptu i uzyskać te same wyniki, ale tylko wtedy, gdy wykonam skrypt bezpośrednio w powłoce pomocniczej
@chepner przez instalację rzeczy, mam na myśli stworzenie środowiska wirtualnego, aktywowanie tego środowiska wirtualnego, a następnie uruchomienie pip install -r $apath/requirements.txtw tym aktywowanym środowisku. Właśnie dlatego użyłem źródła do wywołania skryptu
1

W ramach prostego obejścia można uruchomić powłokę w bieżącej powłoce i źródle. Coś jak:

  1. Otwórz nowy terminal i ustaw wszystko tak, jak chcesz. Wspomniałeś o niektórych zmiennych środowiskowych i tym podobnych. Ustaw je tutaj.

  2. W tym terminalu uruchom nową powłokę. Na przykład bash.

  3. Rób swoje. Źródło skryptu. Jeśli wyjdzie, zostaniesz wrzucony do pierwszej skorupy i wszystko jest nadal ustawione. Po prostu uruchom bashponownie i wrócisz do pracy.

Aby to zilustrować, stworzyłem ten skrypt, który zawiedzie, jeśli spróbujesz go zdobyć:

$ cat /home/terdon/scripts/bar.sh
set -o errexit
var='bar

Zobaczmy, co się stanie, jeśli rozpocznę zagnieżdżoną sesję powłoki, a następnie ją źródła (zwróć uwagę, że używam przenośnej nazwy dla sourcepolecenia .; sourceto bashism):

parent-shell $ bash      ## start a new shell
child-shell $ . ~/scripts/bar.sh
bash: /home/terdon/scripts/bar.sh: line 2: unexpected EOF while looking for matching `''
parent-shell $ 

Jak widać, błąd składniowy spowodował zamknięcie skryptu źródłowego, co z kolei spowodowało zamknięcie mojej sesji powłoki, ale ponieważ była to sesja zagnieżdżona, po prostu wylądowałem z powrotem w oryginalnej, macierzystej powłoce ze wszystkimi ustawionymi zmiennymi . Teraz po prostu uruchom ponownie nową powłokę i możesz wrócić do pozyskiwania skryptu.

terdon
źródło
Spróbuję tego naprawdę szybko
Ma to zamierzony efekt ... wadą jest to, że zmienne, które tworzę dla powłoki nadrzędnej, nie są dostępne w powłoce podrzędnej, która zawiera jedną ze zmiennych potrzebnych do wykonania w powłoce podrzędnej. Czy istnieje sposób na odrodzenie podpowłoki z pliku, który wykonuję? W ten sposób nadal mogę wywoływać skrypt w powłoce nadrzędnej i nadal mogę uzyskać dostęp do zmiennych, których potrzebuję? Dosłownie ustawiam się create_path=~/Desktop/site_builder/create.sh w powłoce nadrzędnej, ponieważ robię to tak często. Potrzebuję go do wywołania source $ create_path [argument] w celu wykonania skryptu.
1
@JillRussek, jeśli zmienne nie są przekazywane do powłoki potomnej, to ich nie kopiujesz export. Ale to, co opisujesz, naprawdę ma bardzo niewielki sens. Brzmi coraz bardziej jak problem XY . Możesz opublikować nowe pytanie wyjaśniające, jaki jest twój cel końcowy. Założę się, że możemy dać ci lepsze rozwiązanie niż wszystkie te dziwne pozyskiwanie.
terdon
Hmm Też mogę spróbować. W tej chwili po prostu odradzanie powłoki potomnej ze skryptu zamiast z terminala robi dokładnie to, co chcę. Muszę pobrać skrypt z terminala, aby stworzyć wirtualne środowisko w skrypcie i zainstalować w nim rzeczy. Teraz działa zgodnie z przeznaczeniem.
Ale masz rację, nie eksportowałem zmiennych, ponieważ nie wiedziałem, że muszę: D. (Nigdy wcześniej nie