Wyjdź z terminala po uruchomieniu skryptu bash

18

Próbuję napisać bashskrypt, aby otworzyć niektóre pliki (głównie pliki pdf) za pomocą gnome-openpolecenia. Chcę również, aby terminal zakończył pracę po otwarciu pliku pdf.

Próbowałem dodać exitna końcu mojego skryptu, ale to nie zamyka terminalu. Próbowałem znaleźć w Internecie odpowiedź na moje pytanie, ale nie mogłem znaleźć żadnej właściwej. Byłbym bardzo wdzięczny, gdybyście mogli pomóc.

Potrzebuję odpowiedzi, która zabija tylko terminal, z którego uruchamiam polecenie, nie wszystkie terminale, czy byłoby to możliwe? Poprzednia odpowiedź, którą zaakceptowałem, zabija wszystkie otwarte okna terminali. Do dzisiaj nie zdawałem sobie sprawy, że tak jest.

Rumesh
źródło
Czy uruchamiasz skrypt w terminalu? Ściśle z wiersza poleceń nie ma powodu, aby otwierać terminal w tym celu.
Jacob Vlijm,
Tak, uruchamiam skrypt z terminala. Nie zdawałem sobie sprawy, że istnieje różnica między terminalem a wierszem poleceń
Rumesh,
I otrzymuje gnome-opensię xdg-openw moim skrypcie, ale nie ma zmian. Terminal nadal pozostaje otwarty
Rumesh
@ Tim Wow, to działa =) +1
AB
@Tim Ale moje rozwiązanie też nie było złe. ;)
AB

Odpowiedzi:

12

Jeśli otwierasz tylko jeden plik, tak naprawdę nie musisz używać skryptu, ponieważ skrypt ma być łatwym sposobem uruchamiania wielu poleceń z rzędu, podczas gdy tutaj wystarczy uruchomić dwa polecenia (w tym exit) .

Jeśli chcesz uruchomić exitpo poleceniu lub po łańcuchu poleceń, możesz połączyć go z tym, co już masz, używając &&operatora (który w przypadku powodzenia poprzedniego polecenia / łańcucha poleceń wykona następne polecenie) lub za pomocą ;operator (który zarówno w przypadku powodzenia, jak i niepowodzenia poprzedniego polecenia / łańcucha poleceń wykona następne polecenie).

W tym przypadku byłoby to coś takiego:

gnome-open <path_to_pdf_file> && exit

* <ścieżka_do_pliku_pfd> = ścieżka do pliku pdf

exitumieszczony na końcu skryptu nie działa, ponieważ po prostu wychodzi z bashinstancji, w której skrypt jest uruchamiany, czyli innej bashinstancji niż wewnętrzna bashinstancja terminala .

Jeśli mimo wszystko chcesz użyć skryptu, najprostszym sposobem jest wywołanie skryptu w następujący sposób:

<path_to_script> && exit

Lub jeśli skrypt znajduje się w bieżącym katalogu roboczym terminala, tak:

./<script> && exit

Jeśli naprawdę nie chcesz / nie możesz tego zrobić, drugim najprostszym sposobem jest dodanie tej linii na końcu skryptu:

kill -9 $PPID

Spowoduje to wysłanie SIGKILLsygnału do procesu macierzystego skryptu ( bashinstancja połączona z terminalem). Jeśli tylko jedna bashinstancja jest powiązana z terminalem, zabicie spowoduje, że terminal sam się zamknie. Jeśli wiele bashwystąpień jest połączonych z terminalem, to zabicie nie spowoduje zamknięcia się terminalu.

kos
źródło
2
Sygnał SIGTERM jest wysyłany do procesu z prośbą o jego zakończenie. W przeciwieństwie do sygnału SIGKILL, proces może go wychwycić, zinterpretować lub zignorować. Pozwala to procesowi wykonać niezłe zakończenie, zwalniając zasoby i zapisując stan w razie potrzeby. SIGINT jest prawie identyczny jak SIGTERM.
AB
@AB Masz rację, SIGTERMtutaj nie wystarczy.
kos
Dziękuję za odpowiedź. Chyba źle używam tylko jednego polecenia
podanego
kill $ PPID robi to samo co exit - nic. A kill -9 $ PPID zamyka wszystkie okna potomne wraz z rodzicem.
SDsolar
5

Ten skrypt kończy terminal, a tym samym powłokę i siebie.

Bezlitośnie zabija wszystkie procesy. Jeśli w terminalu jest otwartych wiele kart, są one również zamknięte.

Problem polega na tym, że jeśli otwartych jest kilka terminali, a są to procesy potomne gnome-terminal-server, wszystkie terminale zostaną zabite.

W takim przypadku skrypt powinien zostać uruchomiony w niezależnym terminalu, np xterm

<your_command> & disown

PPPID=$(awk '{print $4}' "/proc/$PPID/stat")
kill $PPPID
  • PPID

    PPID jest identyfikatorem procesu nadrzędnego, w tym przypadku shell ( e.g. /bin/bash)

  • PPPID

    PPPID to identyfikator procesu nadrzędnego PPID, w tym przypadku okno terminala

  • <your_command> & disown

    W powłoce bash wbudowane polecenie disown służy do usuwania zadań z tabeli zadań lub oznaczania zadań, aby sygnał SIGHUP nie był do nich wysyłany, jeśli powłoka nadrzędna je odbierze (np. Jeśli użytkownik się wyloguje).

  • awk '{print $4}' "/proc/$PPID/stat"

    Pobiera wartość czwartej kolumny pliku /proc/$PPID/stat(np /proc/1/stat. Zwraca 0)

AB
źródło
Myślę, że polecenie $$ get jest pid terminala ... Czy to byłaby alternatywa? Czy mógłbyś również wyjaśnić, jak się wyprzeć?
Tim
Jak ten skrypt to robi? Nadal jestem nowy w skryptowaniu powłoki, więc naprawdę nie rozumiem tych poleceń. Czy możesz wyjaśnić, w jaki sposób zamyka terminal
Rumesh,
1
@ Czas Nie, zwraca powłokę w terminalu: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB
1
@RumeshSudhaharan Zabija całe okno terminala, w którym skrypt jest uruchamiany, ale nie ma innych okien terminala.
AB
3
@AB wcześniej powiedziałeś, że to tylko zabija bieżące okno terminala, a nie żadne z pozostałych. Użyłem tego skryptu dzisiaj z dwoma otwartymi oknami terminala i oba zostały zabite po uruchomieniu skryptu.
Rumesh
4

Możesz użyć .exec ./your-script

Emulator terminala, taki jak GNOME Terminal, kończy działanie, gdy początkowy proces w nim działający - zwykle jest to powłoka - kończy działanie.

Jeśli jesteś już w terminalu i jedyną rzeczą, którą chcesz zrobić przed zamknięciem tego terminalu, jest uruchomienie określonego skryptu (lub programu), oznacza to, że nie potrzebujesz już powłoki, która w nim działa. W ten sposób możesz użyć execwbudowanej powłoki, aby powłoka zastąpiła się procesem utworzonym przez twoje polecenie.

  • W przypadku skryptu jest to kolejny proces powłoki - podobnie jak tworzenie drugiego procesu powłoki po uruchomieniu skryptu bez exec.

Składnia jest np .exec commandexec ./your-script

exec: przykład

Załóżmy na przykład, że mam skrypt powłoki o nazwie count, oznaczony jako wykonywalny i umieszczony w bieżącym katalogu. Zawiera:

#!/usr/bin/env bash
for i in {5..1}; do echo $i; sleep 1; done

I w terminalu uruchamiam:

exec ./count

Drukuje cyfry 5, 4, 3, 2i 1jeden za drugim, a następnie końcowe okno zostanie zamknięte.

Jeśli uruchomisz to z czegoś innego niż pierwszy proces uruchamiany w twoim terminalu - na przykład, jeśli bashnajpierw uruchomiłeś, aby uruchomić inną instancję powłoki - to spowoduje to powrót do powłoki, która utworzyła ten proces, zamiast wychodzenia z terminalu. (To zastrzeżenie dotyczy w równym stopniu exitmetod opartych na bazach danych).

Możesz użyć ../your-script; exit

Jeśli nie chcesz, aby twoja powłoka zastąpiła się nowym procesem (via exec), możesz nakazać mu pozostanie, ale opuści się natychmiast po zakończeniu nowego procesu.

Aby to zrobić, uruchom polecenie i exitpolecenie, oddzielając je, ;aby można je było podać w jednym wierszu.

Składnia jest command; exitnp ../your-script; exit

command; exit vs. command && exit

Możesz zauważyć, że wygląda to podobnie do metody sugerowanej w odpowiedziach kos i heemayl . Różnica polega na tym, że:./your-script && exit

  • &&uruchamia drugie polecenie tylko wtedy, gdy pierwsze polecenie zgłosiło, że powiodło się, zwracając kod wyjścia równy zero.
  • ; uruchamia drugie polecenie niezależnie od tego, czy pierwsze polecenie zgłosiło powodzenie.

Który chcesz zależy od konkretnej sytuacji. Jeśli polecenie nie powiedzie się, czy chcesz, aby powłoka wywołująca (i terminal hostujący) pozostała aktywna? Jeśli tak, użyj &&; jeśli nie, użyj ;.

Istnieje również command || exit, który zamyka powłokę wywołującą tylko w przypadku commandzgłoszenia awarii .

Eliah Kagan
źródło
2

Możesz pobrać skrypt zamiast go uruchamiać np

$ cat run.sh
exit;
$ ./run.sh #will not close
$ . ./run.sh # will close
RiaD
źródło
1

Osobiście wykonałbym polecenie, aby otworzyć pdf lub inne pliki w podpowłoce, opóźnić zezwolenie na otwarcie plików, a następnie wyjść. Zasadniczo oto, co przetestowałem(nohup gnome-open *.pdf &); sleep 2; exit

Różnica w tym zakresie byłaby nohup gnome-open *.pdf && sleep 2 && exit

Sergiy Kolodyazhnyy
źródło
W moim przypadku, ponieważ nohupignoruje sygnał rozłączenia, nohup xdg-open some_programdziałał dla mnie i exitbył niepotrzebny. nohupprzekierowuje wiadomość do nohup.outpliku:nohup: ignoring input and appending output to nohup.out
nick indiessance
0

Najprostszym rozwiązaniem byłoby:

xdg-open file.pdf && exit

W przeciwieństwie do innych podobnych poleceń nohupnie jest konieczne, aby polecenie zostało zignorowane SIGHUP, przyczyną jest xdg-openzakończenie procesu odradzania procesu potomnego, który jest preferowaną aplikacją do otwierania pliku pdf. Ponieważ faktyczny proces rozpoczęty z terminala nie jest już tam do zabicia, nohupnie jest potrzebny.

&&wskazuje, że następne polecenie zostanie uruchomione, jeśli poprzednie polecenie zakończy się powodzeniem, tj. zwróci kod wyjścia 0( $?=0) i exitpo prostu zamknie terminal.

heemayl
źródło
Myślę, że powiedział, że wyjście nie działa ...
Tim
@Tim: Być może OP nie wykorzystał go we właściwy sposób, od pytania jest dla mnie bardzo niejasne, jak on postawił exitna końcu i nie działał ..
heemayl
1
@Tim Ponieważ OP umieścił exitw skrypcie, co jest nieużyteczne, ponieważ powoduje wyjście z bashinstancji, w której skrypt jest wykonywany, a nie z bashinstancji nadrzędnej (połączonej z terminalem), co spowodowałoby zamknięcie terminalu
kos
1
W każdym razie xdg-opendziała już w tle i jest odłączony od terminala, więc nie potrzebujesz nohuptutaj, a ponadto z tego, co rozumiem, OP uruchamia się xdg-openwiele razy w skrypcie, aby otwierać wsadowo wiele plików, użycie xdg-opentego w skrypcie spowodowałoby skrypt do zjazdu na pierwszym xdg-openwystąpieniem
kos
@kos: Nie, nie działam xdg-openw tle, nawet jeśli miałem nohupto z innego powodu i muszę tam być .. każdy proces w tle z terminala źródłowego zostanie zabity, gdy zabijesz terminal nadrzędny .. nohupjest to, aby zapobiec to ... ponieważ nie muszę ponownie używać terminala interaktywnie, nie ma potrzeby umieszczania procesu w bg.. w drugim punkcie, któremu można również zapobiec, uruchamiając każdy xdg-open && exitw podpowłoce ..
heemayl
0

Aby wyraźnie odpowiedzieć na pytanie tytułowe,

„Wyjdź z terminala po uruchomieniu skryptu bash” :

Uruchom tylko skrypt w terminalu

Nie patrząc na szczegóły działania skryptu, skrypt można uruchomić bezpośrednio w terminalu za pomocą opcji -e( --command), bez uruchamiania powłoki - jest on używany zamiast powłoki:

gnome-terminal -e ./script.sh

Użyj opcji -x( --execute), jeśli chcesz podać argumenty do skryptu. Dzięki temu cała reszta wiersza poleceń jest traktowana jako polecenie i argumenty.

gnome-terminal -x ./script.sh foo bar

Jeśli skrypt zakończy działanie, nie ma interaktywnej powłoki, która mogłaby zatrzymać wszystko, czekając na dane wejściowe użytkownika.

Przykłady

Teminal zakończy działanie po wyjściu z uruchomionego polecenia - w ten sposób zamknie się po sleepuruchomieniu 4 sekund, bez powłoki:

gnome-terminal -x sleep 4

Oczywiście możesz nadal używać skryptów powłoki, ponieważ twój skrypt i tak używa innej instancji powłoki.

Możesz także uruchomić powłokę z jawnym skryptem - nie będzie interaktywny:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Volker Siegel
źródło