Jak całkowicie odłączyć proces od terminalu?

304

Używam Tilda (rozwijanego terminala) na Ubuntu jako „centrum dowodzenia” - podobnie jak inni mogą używać GNOME Do, Quicksilver lub Launchy.

Mam jednak problem z tym, jak całkowicie odłączyć proces (np. Firefox) od terminala, z którego został uruchomiony - tj. Zapobiec, aby taki (nie) proces potomny

  • zostaje zakończone po zamknięciu terminalu źródłowego
  • „zanieczyszcza” terminal źródłowy przez STDOUT / STDERR

Na przykład, aby uruchomić Vima w „właściwym” oknie terminala, wypróbowałem prosty skrypt, taki jak poniżej:

exec gnome-terminal -e "vim $@" &> /dev/null &

Jednak nadal powoduje to zanieczyszczenie (również przekazanie nazwy pliku nie wydaje się działać).

slhck
źródło
1
To także dobre pytanie. Myślę, że sprawiedliwie jest uznać Bash za język programowania - chociaż w rzeczywistości zakres tego pytania jest prawdopodobnie bardziej po stronie sysadmin ...
To jest duplikat tego pytania stackoverflow.com/questions/285015/...
Dana the Sane
Twój przypadek użycia sam w sobie nie opisuje całkowitego oderwania.
jiggunjer

Odpowiedzi:

344

Po pierwsze; po rozpoczęciu procesu możesz go ustawić w tle, najpierw zatrzymując go (hit Ctrl- Z), a następnie pisząc, bgaby wznowić działanie w tle. Teraz jest to „zadanie”, a jego stdout/ stderr/ stdinsą nadal podłączone do twojego terminala.

Możesz natychmiast rozpocząć proces w tle, dodając na końcu „&”:

firefox &

Aby uruchomić go w tle wyciszonym, użyj tego:

firefox </dev/null &>/dev/null &

Niektóre dodatkowe informacje:

nohupto program, którego można użyć do uruchomienia aplikacji w taki sposób, że jego stdout / stderr może być zamiast tego wysłany do pliku i taki, że zamknięcie skryptu nadrzędnego nie ZWIĘKSZA dziecka. Jednak przed uruchomieniem aplikacji musisz mieć prognozę, aby z niej skorzystać. Ze względu na sposób nohupdziałania nie można go po prostu zastosować do uruchomionego procesu .

disownto wbudowane bash, które usuwa zadanie powłoki z listy zadań powłoki. Zasadniczo oznacza to, że nie możesz już na nim używać fg, bgale co ważniejsze, gdy zamkniesz skorupę, nie będzie się ona zawieszać ani wysyłać SIGHUPdo tego dziecka. W przeciwieństwie do nohup, disownjest używany po uruchomieniu procesu i uruchomieniu go w tle.

To, czego nie możesz zrobić, to zmienić stdout / stderr / stdin procesu po jego uruchomieniu. Przynajmniej nie z muszli. Jeśli uruchomisz proces i powiesz mu, że jego stdout jest terminalem (co robisz domyślnie), wówczas proces ten jest skonfigurowany tak, aby wyświetlał dane w terminalu. Twoja powłoka nie ma nic wspólnego z konfiguracją FD procesów, jest to po prostu coś, czym sam proces zarządza. Sam proces może zdecydować, czy zamknąć stdout / stderr / stdin, czy nie, ale nie możesz użyć powłoki, aby to zmusić.

Aby zarządzać danymi wyjściowymi procesu w tle, masz wiele opcji ze skryptów, prawdopodobnie „nohup” jako pierwszy. Ale dla interaktywnych procesów zaczynasz, ale zapomniałeś uciszyć ( firefox < /dev/null &>/dev/null &), tak naprawdę niewiele możesz zrobić.

Polecam dostać GNU screen. Za pomocą screena możesz po prostu zamknąć działającą powłokę, gdy wynik procesu staje się kłopotliwy i otworzyć nową ( ^Ac).


Aha, a przy okazji, nie używaj „ $@” tam, gdzie go używasz.

$@oznacza $1, $2, $3..., które mogłyby włączyć polecenie na:

gnome-terminal -e "vim $1" "$2" "$3" ...

Prawdopodobnie nie tego chcesz, ponieważ -e bierze tylko jeden argument. Użyj, $1aby pokazać, że twój skrypt może obsłużyć tylko jeden argument.

Naprawdę trudno jest uzyskać prawidłowe działanie wielu argumentów w scenariuszu, który podałeś (wraz z gnome-terminal -e), ponieważ -ebierze tylko jeden argument, który jest ciągiem poleceń powłoki. Musisz zakodować swoje argumenty w jeden. Najlepszy i najbardziej niezawodny, ale raczej niezbyt gęsty sposób:

gnome-terminal -e "vim $(printf "%q " "$@")"
lhunath
źródło
Wielkie dzięki za to! Niestety mogę zaakceptować tylko jedną odpowiedź. Skończyło się na „nohup $ @ &> / dev / null &” i „alias wvim = 'launch.sh gnome-terminal -x vim'”
20
Co za fantastycznie szczegółowa i pouczająca odpowiedź. +1
Teekin,
1
@ Hi-Angel, kiedy zamykasz interaktywną powłokę bash, bash HUP wykonuje wszystkie aktywne zadania. Kiedy ^ Z i bg proces nadal jest zadaniem, czy to w tle. Aby usunąć go jako zadanie, użyj disown, a następnie proces będzie kontynuowany po zamknięciu powłoki, ponieważ bash nie będzie go HUP.
lhunath
3
Nie użyjesz $*zamiast $@naprawić problemu z oddzielnymi ciągami?
sjas
2
To, czego nie możesz zrobić, to zmienić stdout / stderr / stdin procesu po jego uruchomieniu. - niezupełnie prawda. Użyj reptyrdo tego.
Stefan Seidel
198
nohup cmd &

nohup całkowicie odłącza proces (demonizuje go)

dsm
źródło
5
Chociaż zwięzłość jest cenna, kompletność jest cenniejsza. Chociaż nohup jest jądrem GNU, odpowiednia będzie tylko odpowiedź bash (lub uwaga na to, że jej nie ma). Niemniej jednak dobra odpowiedź.
Ograniczone Zadośćuczynienie
23
nohuppo prostu ignoruje SIGHUPsygnał. Wykonuje proces normalnie. Bez demonizacji.
nemo
1
@nemo Co oznacza, że ​​proces nie jest odłączony, ale zostałby odłączony (i dziecko init), gdyby powłoka została zamknięta ... prawda?
Noldorin
@Noldorin Tak. Zignorowanie SIGHUP, które jest wysyłane po zakończeniu powłoki, spowoduje, że proces potomny będzie działał i zostanie przeniesiony do init.
nemo
@nemo nohup również wycisza standardowe wejścia / wyjścia. Kontynuuj z disown, aby całkowicie odłączyć.
jiggunjer
60

Jeśli używasz bash, spróbuj ; patrz bash (1) .disown [jobspec]

Innym podejściem, które możesz wypróbować, jest at now. Jeśli nie jesteś superużytkownikiem, twoja zgoda na użycie atmoże być ograniczona.

Randy Proctor
źródło
„disown” nie wydaje się wewnętrznym poleceniem bash (niedostępne na moim komputerze i używam bash). „nohup”, jak zasugerował Ben, może być znacznie lepszym (i standardowym) sposobem na zrobienie tego.
1
nigdy nie myślałem o użyciu „at”, dzięki za pomysł!
cadrian
1
atdelegować egzekucję komuś innemu, podoba mi się! +1
Ninsuo,
1
Jako punkt odniesienia to również działa zsh.
Coderer
1
Ponadto, disownwydaje się nie mieć pożądany efekt z gnome-terminal- disownred procesy są nadal zabity, gdy wyjść terminala. Chciałbym wiedzieć, dlaczego / jak.
Kyle Strand
38

Czytając te odpowiedzi, miałem początkowe wrażenie, że wydanie nohup <command> &będzie wystarczające. Działając zsh w gnome-terminal, odkryłem, że nohup <command> &nie powstrzymało to mojej powłoki przed zabijaniem procesów potomnych przy wyjściu. Chociaż nohupjest to użyteczne, szczególnie w przypadku nieinteraktywnych powłok, gwarantuje to tylko wtedy, gdy proces potomny nie zresetuje swojego modułu obsługi SIGHUPsygnału.

W moim przypadku nohuppowinien był uniemożliwić dotarcie do aplikacji sygnałów rozłączenia, ale aplikacja podrzędna (w tym przypadku VMWare Player) resetuje swoją SIGHUPprocedurę obsługi. W rezultacie, gdy emulator terminala zostanie zamknięty, nadal może zabić twoje podprocesy. O ile mi wiadomo, można to rozwiązać tylko poprzez usunięcie procesu z tabeli zadań powłoki. Jeśli nohupzostanie zastąpione przez wbudowaną powłokę, jak to czasami bywa, może to jednak wystarczyć w przypadku, gdy nie jest to ...


disownPowłoka jest wbudowane w bash, zshi ksh93,

<command> &
disown

lub

<command> &; disown

jeśli wolisz jednowarstwowe. Ma to ogólnie pożądany efekt usunięcia podprocesu z tabeli zadań. Umożliwia to wyjście z emulatora terminala bez przypadkowego sygnalizowania procesu potomnego. Bez względu na to, SIGHUPjak wygląda program obsługi, nie powinno to zabić Twojego procesu potomnego.

Po odrzuceniu proces jest nadal dzieckiem emulatora terminala (pobaw się, pstreejeśli chcesz obejrzeć to w akcji), ale po wyjściu emulatora terminala powinieneś zobaczyć, że jest on dołączony do procesu init. Innymi słowy, wszystko jest tak, jak powinno być i jak zapewne chcesz.

Co zrobić, jeśli twoja powłoka nie obsługuje disown? Zdecydowanie opowiadam się za przejściem na taki, który ma taką możliwość, ale przy braku tej opcji masz kilka możliwości.

  1. screeni tmuxmogę rozwiązać ten problem, ale są to rozwiązania znacznie cięższe i nie lubię ich uruchamiać do tak prostych zadań. Są one znacznie bardziej odpowiednie w sytuacjach, w których chcesz zachować tty, zwykle na zdalnym komputerze.
  2. Dla wielu użytkowników może być pożądane sprawdzenie, czy twoja powłoka obsługuje takie funkcje jak zsh setopt nohup. Można tego użyć, aby określić, że SIGHUPnie należy wysyłać do zadań w tabeli zadań po wyjściu powłoki. Możesz albo zastosować to tuż przed wyjściem z powłoki, albo dodać ją do konfiguracji powłoki, tak ~/.zshrcjakbyś zawsze tego chciał.
  3. Znajdź sposób edycji tabeli zadań. Nie mogłem znaleźć sposobu na zrobienie tego w tcshlub csh, co jest nieco niepokojące.
  4. Napisz mały program w C, aby oddzielić i exec(). To bardzo słabe rozwiązanie, ale źródło powinno składać się z kilkudziesięciu wierszy. Następnie można przekazać polecenia jako argumenty wiersza polecenia do programu w języku C, a tym samym uniknąć wpisu specyficznego dla procesu w tabeli zadań.
Stephen Rosen
źródło
29
  1. nohup $COMMAND &
  2. $COMMAND & disown
  3. setsid command

Używam numeru 2 od bardzo dawna, ale numer 3 działa równie dobrze. Ponadto, disownposiada nohupflagę -h, może wyprzeć wszystkie procesy z -a, a może wyprzeć wszystkie procesy uruchomione z -ar.

Uciszenie jest realizowane przez $COMMAND &>/dev/null.

Mam nadzieję że to pomoże!

Pan Minty Fresh
źródło
Krótkie i słodkie; dzięki za to bardzo pomocne podsumowanie!
Sheljohn,
Nie mogę uwierzyć, że wciąż otrzymuję powiadomienia o tym poście ...
Pan Minty Fresh
9

Myślę, że ekran może rozwiązać twój problem


źródło
9

w tcsh (i być może także w innych powłokach) możesz użyć nawiasów, aby odłączyć proces.

Porównaj to:

> jobs # shows nothing
> firefox &
> jobs
[1]  + Running                       firefox

Do tego:

> jobs # shows nothing
> (firefox &)
> jobs # still shows nothing
>

To usuwa firefoxa z listy zadań, ale nadal jest powiązany z terminalem; jeśli zalogowałeś się do tego węzła przez 'ssh', próba wylogowania nadal zawiesza proces ssh.

Nathan Fellman
źródło
9

Najprostsza i jedyna poprawna odpowiedź na bash:

command & disown

Nie musisz odłączać procesu od terminala, ale od powłoki.

ManuelSchneid3r
źródło
7

Aby oddzielić powiązanie powłoki tty, uruchom polecenie przez podpowłokę np

(Komenda)&

Po wyjściu używany terminal jest zamknięty, ale proces jest nadal aktywny.

sprawdź -

(sleep 100) & exit

Otwórz inny terminal

ps aux | grep sleep

Proces wciąż trwa.

jitendra
źródło
Właśnie tego potrzebowałem. Próbowałem dodać skrót konsoli do wysublimowanego tekstu i działa idealnie, oto co skończyłem z: ("/ opt / Sublime Text 2 / sublime_text" $ @) &
Ron E
5

Tworzenie tła i planowanie zadania jest prawdopodobnie jedną z pierwszych rzeczy, o których powinien wiedzieć każdy administrator systemu Unix.

Oto jak to się robi z bash:

./script.sh
# suspend process
{ctrl-Z}
# background process
bg
# list all backgrounded jobs
jobs
# bring it back to foreground
fg
djangofan
źródło
4

Możesz uruchomić polecenie za pomocą polecenia nohup, to odłączy proces i przekieruje dane wyjściowe do danego pliku ... ale nie jestem pewien, czy dokładnie tego potrzebujesz.

Ben
źródło
Mógłbym przysiąc, że próbowałem nohup przed użyciem exec - ale najwyraźniej nie działa poprawnie, ponieważ działa to tak: nohup gnome-terminal -e "vim $ @" &> / dev / null &
2

Wypróbuj demona - powinien być dostępny od przyjaznego menedżera pakietów i kompleksowo zadbać o każdy sposób odłączenia się od terminala.

ShiDoiSi
źródło
2

Po prostu dodaj to do swojego bashrc / zshrc:

detach() {
  "$@" 1>/dev/null 2>/dev/null &; disown
}

Następnie możesz uruchomić odrzucone polecenia w następujący sposób:

detach gedit ~/.zshrc
B. Oddział
źródło
1

W moim .bashrc mam te funkcje właśnie w tym celu:

function run_disowned() {
    "$@" & disown
}

function dos() {
    # run_disowned and silenced

    run_disowned "$@" 1>/dev/null 2>/dev/null
}

Prefiks polecenia, dosaby uruchomić go odłączony od terminala.

Funkcja jest napisana do pracy z bashi zsh.

mic_e
źródło
1
Jestem nieco mylić, dlaczego ta odpowiedź wykorzystuje jedną funkcję zawinięty do innego, gdy jej wystarcza po prostu użyć jednej funkcji z ciałem tak: ( "$@" & disown) &> /dev/null. Nie ma też większego sensu w użyciu, 1>a 2>ponieważ używasz disown, co oznacza, że ​​używasz bash, a w bash możesz po prostu zrobić &>przekierowanie zarówno stdout, jak i stderr
Sergiy Kolodyazhnyy
Mam to jako dwie funkcje, ponieważ (1) myślę, że łatwiej jest czytać w ten sposób, i (2) Potrzebuję run_disownedfunkcjonalności w innych miejscach w moich plikach dot. Oczywiście masz rację &>.
mic_e
0

W systemie Mac OS X znalazłem, że muszę używać zarówno nohup AND disown, aby upewnić się, że proces potomny nie zostanie zerwany z terminalem.

aaron
źródło
0

Aby to zrobić, używam następującego skryptu. Zatrzymuje drukowanie procesu do terminala, odłącza się nohupi kończy ze statusem powrotu, jeśli polecenie zakończy się w ciągu TIMEOUT.

#!/bin/bash

TIMEOUT=0.1

CMD=( "$@" )
#Could have some shortcuts here, e.g. replace "somefile.c" with "gedit somefile.c"

#use nohup to run the command, suppressing its output and allowing the terminal to be closed
#also send nohup's output to /dev/null, supressing nohup.out
#run nohup in the background so this script doesn't block
#print the command for debugging and to see bash variable expansion
printf "%q " "${CMD[@]}"
echo
nohup "${CMD[@]}" >/dev/null 2>&1 &
NOHUP_PID=$!

#kill this script after a short time, exiting with success status - command is still running
#this is needed as there is no timeout argument for `wait` below
MY_PID=$$
trap "exit 0" SIGINT SIGTERM
sleep $TIMEOUT && kill $MY_PID 2>/dev/null & #ignore "No such process" error if this exits normally

#if the command finishes before the above timeout, everything may be just fine or there could have been an error
wait $NOHUP_PID
NOHUP_STATUS=$?
#print an error if there was any. most commonly, there was a typo in the command
[ $NOHUP_STATUS != 0 ] && echo "Error: $CMD"
#return the exit status of nohup, whatever it was
exit $NOHUP_STATUS

Przykład użycia:

>>> run false
false
Error: false
>>> echo $?
1
>>> run true
true
>>> run sleep 10
sleep 10
>>>
jozxyqk
źródło
0

sudo apt install ucommon-utils

pdetach command

Proszę bardzo :)

d4rk4ng31
źródło
-1

Wiele odpowiedzi sugerowało użycie nohup . Wolałbym raczej użyć pm2 . Korzystanie PM2 nad nohup ma wiele zalet, takich jak utrzymywanie aplikacja żywy, utrzymania logów dla aplikacji i wiele więcej innych funkcji. Aby uzyskać więcej informacji, sprawdź to .

Aby zainstalować pm2 , musisz pobrać npm . Dla systemu opartego na Debianie

sudo apt-get install npm

i dla Redhata

sudo yum install npm

Lub możesz postępować zgodnie z tymi instrukcjami . Po zainstalowaniu npm użyj go, aby zainstalować pm2

npm install pm2@latest -g

Po zakończeniu możesz rozpocząć aplikację

$ pm2 start app.js              # Start, Daemonize and auto-restart application (Node)
$ pm2 start app.py              # Start, Daemonize and auto-restart application (Python)

Do monitorowania procesu użyj następujących poleceń:

$ pm2 list                      # List all processes started with PM2
$ pm2 monit                     # Display memory and cpu usage of each app
$ pm2 show [app-name]           # Show all informations about application

Zarządzaj procesami przy użyciu nazwy aplikacji lub identyfikatora procesu lub zarządzaj wszystkimi procesami jednocześnie:

$ pm2 stop     <app_name|id|'all'|json_conf>
$ pm2 restart  <app_name|id|'all'|json_conf>
$ pm2 delete   <app_name|id|'all'|json_conf>

Pliki dziennika można znaleźć w

$HOME/.pm2/logs #contain all applications logs
haccks
źródło
1
Korzystanie z aplikacji NodeJS (w przeciwieństwie do małego i solidnego polecenia, takiego jak nohup) w celu kontrolowania procesów uniksowych wydaje się ... naprawdę przesadne i, szczerze mówiąc, raczej dziwne. Użyłbym monit, jeśli potrzebujesz funkcji restartowania.
Sergio
@Sergio to Twój wybór, aby korzystać z deprecjonowanej aplikacji.
haccks
W tym roku wydano kilka wydań (jedno 4 dni temu), więc nie rozumiem, dlaczego / dlaczego uważasz, że monit jest przestarzałą aplikacją. @ patrz mmonit.com/monit/changes
Sergio
Mówiłem o nohup.
haccks
1
nohupjest zwykłym standardowym poleceniem POSIX, więc ta sama uwaga: nie ma mowy, żeby był przestarzały. @see unix.com/man-page/posix/1p/nohup
Sergio
-1

Jeśli Twoim celem jest po prostu uruchomienie aplikacji wiersza polecenia bez pozostawiania okna terminala, możesz spróbować uruchomić aplikację po uruchomieniu terminalu z alt-F2.

MattKelly
źródło