So starten Sie eine Anwendung „richtig“ von einer Shell aus


21

Es fällt mir schwer, die Frage genau zu formulieren, aber ich werde mein Bestes geben. Ich benutze dwmals Standard Windows Manager unddmenuals mein Anwendungsstarter. Abgesehen von meinem Browser verwende ich kaum GUI-Anwendungen. Die meiste Arbeit erledige ich direkt über die Kommandozeile. Außerdem bin ich ein großer Fan von Minimalismus in Bezug auf Betriebssysteme, Anwendungen usw. Eines der Tools, das ich nie losgeworden bin, war ein Anwendungsstarter. Hauptsächlich, weil ich nicht genau verstehe, wie Anwendungsstarter funktionieren / was sie tun. Sogar umfangreiche Internetrecherchen zeigen nur vage Erklärungen. Was ich tun möchte, ist, sogar meinen Anwendungsstarter loszuwerden, da ich, abgesehen vom eigentlichen Spawnen der Anwendung, absolut keinen Nutzen dafür habe. Dazu möchte ich wirklich wissen, wie man Anwendungen von der Shell aus "richtig" startet. Wobei die Bedeutung von "richtig" durch "wie ein Anwendungsstarter" angenähert werden kann.

Ich kenne die folgenden Möglichkeiten, um Prozesse aus der Shell zu erzeugen:

  1. exec /path/to/Program Ersetzen Sie die Shell durch den angegebenen Befehl, ohne einen neuen Prozess zu erstellen
  2. sh -c /path/to/Program Starten Sie den Shell-abhängigen Prozess
  3. /path/to/Program Starten Sie den Shell-abhängigen Prozess
  4. /path/to/Program 2>&1 & Starten Sie den Shell-unabhängigen Prozess
  5. nohup /path/to/Program & Starten Sie den Shell-unabhängigen Prozess und leiten Sie die Ausgabe an um nohup.out

Update 1: Ich kann veranschaulichen, was z. B. dmenudie Rekonstruktion von wiederholten Aufrufen ps -eflunter verschiedenen Bedingungen bedeutet. Es wird eine neue Shell erzeugt /bin/bashund als Kind dieser Shell die Anwendung /path/to/Program. Solange das Kind in der Nähe ist, ist die Muschel in der Nähe. (Wie es das schafft, ist mir ein Rätsel ...) Wenn Sie dagegen nohup /path/to/Program &von einer Shell ausgehen, /bin/bashwird das Programm das untergeordnete Element dieser Shell, ABER wenn Sie diese Shell beenden, wird das übergeordnete Element des Programms der oberste Prozess. Wenn also der erste Prozess zB war /sbin/init verboseund es PPID 1dann hat, wird es der Elternteil des Programms sein. Hier ist, was ich anhand eines Diagramms zu erklären versuchte: chromiumWurde gestartet über dmenu, firefoxwurde gestartet mit exec firefox & exit:

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          `-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 `-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         `-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash-+-bash
        |                                                    `-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        `-wpa_supplicant

Update 2: Ich denke, die Frage kann auch auf Folgendes reduziert werden: Was sollte das Elternteil eines Prozesses sein? Soll es zB eine Shell sein oder soll es der initProzess sein, also der Prozess mit PID 1?


3
Die knappe Antwort auf Ihre Frage lautet: "Was auch immer die gewünschten Ergebnisse erzielt."
Wayne Werner

1
Mist, Müll - du stellst ein paar gute Fragen. aber ich denke wayne ist hier auf der nase - fragt dich deine letzte redaktion init- worauf könnte die antwort lauten ... vielleicht? es hängt davon ab, wie / ob Sie mit ihm sprechen möchten, was initSie verwenden und wo sich die Datenkanäle befinden. Im Allgemeinen wird das Zeug dazu neigen, sich von selbst auszuarbeiten - dafür initist es da. In jedem Fall normalerweise dann, wenn Sie einen Prozess dämonisieren init. Oder wenn Sie Auftragssteuerung möchten, aktuelle Shell.
mikeserv

Hahaha, Prost @mikeserv; 4:37 Uhr morgens hier und schon das erste Lachen des Tages. Stimmt, das Zeug klappt immer irgendwie. Ich werde es entfernen dmenuund sehen, wie ich mit dem, was ich gelernt habe, zurechtkomme. Ich finde exec /path/to/Program & exitoder /bin/bash -c /path/to/Program & exitganz brauchbar zu sein. Aber sie alle machen 1also initdie Eltern von Programdenen, die mir recht sind, solange dies Sinn macht und keine *nixGrundprinzipien verletzt .
lord.garbage

@ lord.garbage - das liegt an dir exec &, denke ich. Normalerweise erledige ich meine Sachen nur vom Terminal aus. Vielleicht kann die Frage von Ben Crowell hier etwas nützen . Ich habe dort eine Antwort, aber alle sind sehr gut. Jedenfalls, wenn Sie einen Prozess im Hintergrund haben und sein Elternteil stirbt, wie: sh -c 'cat & kill $$'Sie verwaisen ihn, und es kommt schließlich dazu, dass er geerntet wird. das ist die aufgabe von init - deshalb fallen sie alle darauf herein.
mikeserv

Vielleicht ist eine einfachere Frage nun: Wie ist es möglich , den obigen Prozessbaum aus der Schale zu erhalten: systemd--bash--chromium. Alle Methoden, die ich versuche, führen letztendlich zu einem Prozessbaum der folgenden Form, systemd--chromiumwenn ich Firefox aus der Shell spawne. Wie wird die Muschel hier dämonisiert? Es ist keinem Terminal zugeordnet.
lord.garbage

Antworten:


7

Nun, Sie scheinen ein ziemlich gutes Verständnis dafür zu haben. Um zu klären, was Sie haben,

  • sh -c /path/to/Program ist ziemlich ähnlich zu

    $ sh 
    % / path / to / Program 
    % Ctrl+ D                             (oder Sie könnten " exit " eingeben ) 
    $

    Wenn Sie einen neuen Shell-Prozess starten, geben Sie den Anwendungsbefehlspfad für die neue Shell an und lassen Sie die neue Shell dann beenden. Ich habe die neue Shell zu Illustrationszwecken mit einer anderen Eingabeaufforderung gezeigt. Dies würde im wirklichen Leben wahrscheinlich nicht passieren. Das Konstrukt ist vor allem dann nützlich, wenn Sie knifflige Aufgaben erledigen möchten, z. B. wenn Sie mehrere Befehle in ein Bundle einbinden, sodass sie wie ein einzelner Befehl aussehen (eine Art nicht benanntes Einmalskript) oder wenn Sie komplizierte Befehle erstellen, möglicherweise aus Shell-Variablen. Sie würden es selten nur zum Ausführen eines einzelnen Programms mit einfachen Argumenten verwenden.sh -c "command"

  • 2>&1bedeutet, dass der Standardfehler zur Standardausgabe umgeleitet wird. Das hat nicht wirklich viel damit zu tun &; Sie verwenden es eher, wenn ein Befehl Fehlermeldungen an den Bildschirm sendet, auch wenn Sie sagen, dass Sie die Fehlermeldungen in der Datei erfassen möchten.command > file
  • Das Umleiten der Ausgabe auf nohup.outist ein geringfügiger Nebeneffekt von nohup. Der Hauptzweck von ist die asynchrone Ausführung (allgemein bekannt als "im Hintergrund" oder als "Shell-unabhängiger Prozess", um Ihre Wörter zu verwenden) und die Konfiguration so, dass die Wahrscheinlichkeit größer ist, dass die Ausführung bei Ihnen fortgesetzt werden kann Beenden Sie die Shell (z. B. Abmelden), während der Befehl noch ausgeführt wird.nohup command &command

bash(1)und das Bash-Referenzhandbuch sind gute Informationsquellen.


7

Es gibt verschiedene Möglichkeiten, ein Programm auszuführen und von einem Terminal zu trennen. Eine besteht darin, es im Hintergrund einer Subshell wie folgt auszuführen (durch firefoxIhr Lieblingsprogramm ersetzen ):

(firefox &)

Eine andere ist, den Prozess zu verleugnen:

firefox & disown firefox

Wenn Sie neugierig , wie App Werfer arbeiten, dmenubietet 1 binäre und 2 Shell - Scripts: dmenu, dmenu_pathund dmenu_run, respectively.

dmenu_runleitet die Ausgabe von dmenu_pathin das Menü weiter, das wiederum in die $SHELLVariable weiterleitet, auf die Ihre Variable eingestellt ist. Wenn es leer ist, wird es verwendet /bin/sh.

#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &

dmenu_pathist etwas komplexer, enthält jedoch eine Liste der Binärdateien in Ihrer $PATHUmgebungsvariablen und verwendet nach Möglichkeit einen Cache.

#!/bin/sh
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
        cache=$cachedir/dmenu_run
else
        cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
if stest -dqr -n "$cache" $PATH; then
        stest -flx $PATH | sort -u | tee "$cache"
else
        cat "$cache"
fi

Es ist nicht erforderlich, dass Programme in Shells ausgeführt werden. Eine andere Art zu schreiben dmenu_run, ohne in eine Shell zu pfeifen, wäre:

#!/bin/sh
$(dmenu_path | dmenu "$@") &

6

Ich mag die Antwort von G-Man sehr. Aber ich antworte, weil ich denke, dass Sie Bedenken verwirren. Wie Wayne betont, lautet die beste Antwort "Was auch immer die gewünschten Ergebnisse erzielt".

In der Unix-Prozessverwaltung hat jeder Prozess ein übergeordnetes Element. Die einzige Ausnahme ist der initProzess, der vom Betriebssystem beim Booten gestartet wird. Es ist normal, dass ein übergeordneter Prozess alle untergeordneten Prozesse mitnimmt, wenn er stirbt. Dies erfolgt durch Senden des SIGHUP-Signals an alle untergeordneten Prozesse. Die Standardbehandlung von SIGHUP beendet den Prozess.

Das Shell-Spawnen von Benutzerprozessen unterscheidet sich nicht davon, wenn Sie die Fork- (2) / Exec- (3) -Aufrufe in der Sprache Ihrer Wahl codiert haben . Die Shell ist Ihr übergeordnetes Element. Wenn die Shell beendet wird (z. B. wenn Sie sich abmelden), werden die von ihr erzeugten untergeordneten Prozesse ebenfalls ausgeführt. Die Nuancen, die Sie beschreiben, sind nur Möglichkeiten, dieses Verhalten zu ändern.

exec /path/to/programist wie der Aufruf von exec (3) . Ja, es wird Ihre Shell durch ersetzen program, wobei das übergeordnete Element, das die Shell gestartet hat , erhalten bleibt .

sh -c /path/to/programArt sinnlos erstellt ein Kind Shell-Prozess, der einen Kind-Prozess von erstellen wird program. Dies ist nur dann sinnvoll, wenn /path/to/programes sich tatsächlich um eine Folge von Skriptanweisungen handelt und nicht um eine ausführbare Datei. ( sh /path/to/script.shKann verwendet werden, um ein Shell-Skript auszuführen, dem Ausführungsberechtigungen in einer minderwertigen Shell fehlen.)

/path/to/programErstellt einen "Vordergrund" -Prozess, dh die Shell wartet, bis der Prozess abgeschlossen ist, bevor sie eine andere Aktion ausführt. Im Kontext eines Systemaufrufs ist dies wie bei fork (2) / exec (3) / waitpid (2) . Beachten Sie, dass das untergeordnete Element stdin / stdout / stderr vom übergeordneten Element erbt.

/path/to/program &(Umleitung ignorieren) erzeugt einen "Hintergrundprozess". Der Prozess ist noch ein untergeordnetes Element der Shell, das übergeordnete Element wartet jedoch nicht auf den Abschluss.

nohup /path/to/programruft nohup (1) auf, um das Senden von SIGHUP zu verhindern, programwenn das steuernde Terminal geschlossen ist. Es ist eine Wahl, ob es im Vordergrund oder im Hintergrund ist (obwohl der Prozess am häufigsten im Hintergrund abläuft). Beachten Sie, dass dies nohup.outnur die Ausgabe ist, wenn Sie stdout nicht anderweitig umleiten.

Wenn Sie einen Prozess in den Hintergrund stellen und der übergeordnete Prozess abstirbt, geschieht Folgendes: Wenn das übergeordnete Terminal ein steuerndes Terminal ist , wird SIGHUP an die untergeordneten Terminals gesendet. Ist dies nicht der Fall, ist der Prozess möglicherweise "verwaist" und wird vom initProzess geerbt .

Wenn Sie Eingabe / Ausgabe / Fehler umleiten, verbinden Sie einfach die Dateideskriptoren, die jeder Prozess hat, mit anderen Dateien als denjenigen, die er von seinem übergeordneten Prozess erbt. Nichts davon wirkt sich auf den Prozessbesitz oder die Baumtiefe aus (es ist jedoch immer sinnvoll, alle 3 für Hintergrundprozesse von einem Terminal wegzuleiten).

Nach alledem denke ich nicht, dass Sie sich mit der Erstellung von Prozessen durch die Shell oder Sub-Shells oder Sub-Prozesse befassen sollten, es sei denn, es gibt ein spezifisches Problem, das Sie im Zusammenhang mit der Prozessverwaltung ansprechen.


nitpick: Führt sh -c /path/to/programdas Programm nicht als Shell-Skript aus, wenn die ausführbaren Bits fehlen sh /path/to/program. sh -c /path/to/programwird nur eine Shell öffnen und /path/to/programals Befehl in dieser Shell ausgeführt, was fehlschlägt, wenn sie nicht ausführbar ist.
Filbranden

Nun, wenn wir nicht picken, liegen wir beide falsch. sh -c /path/to/programLiest Befehle /path/to/programals Eingabe in die Shell. Es ist nicht erforderlich, dass die Datei über die Ausführungsberechtigung verfügt, es sollte sich jedoch um ein Shell-Skript handeln
jwm

Hmmm, sh /path/to/programmacht das. Gerade versucht , dass mir: echo echo hello world >abc.sh, dann sh ./abc.shdruckt hello world, während sh -c ./abc.shsagt sh: ./abc.sh: Permission denied(was dasselbe ist , als ob Sie laufen würde ./abc.sh. Direkt in der aktuellen Shell) Habe ich etwas verpasst? (Oder vielleicht habe ich mich im vorherigen Kommentar nicht gut
ausgedrückt

Mein Fehler. sh -c _something_ist dasselbe, als würde man nur _something_an der Eingabeaufforderung tippen, außer dass die untergeordnete Shell erzeugt wird. Sie haben also Recht, dass es fehlschlägt, wenn das Ausführungsbit (als Datei) fehlt. Auf der anderen Seite können Sie eine Reihe von Shell-Befehlen wie bereitstellen sh -c "echo hello world"und es wird gut funktionieren. Es ist also nicht erforderlich, dass das von Ihnen eingegebene Ausführungsbit (oder sogar eine Datei) vorhanden ist, sondern nur, dass der Shell-Interpreter etwas damit anfangen kann.
JWM

Ich glaube, das OP bezog sich auf eine kompilierte oder ausführbare Systemdatei, daher wurde die Ausführungserlaubnis angenommen.
JWM
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.