Cara "benar" memulai aplikasi dari shell

21

Saya merasa sulit untuk mengungkapkan pertanyaan dengan tepat, tetapi saya akan memberikan yang terbaik. Saya menggunakan dwmsebagai manajer jendela default dandmenusebagai peluncur aplikasi saya. Saya jarang menggunakan aplikasi GUI selain dari browser saya. Sebagian besar pekerjaan saya dilakukan langsung dari baris perintah. Selain itu, saya penggemar minimalis tentang sistem operasi, aplikasi, dll. Salah satu alat yang tidak pernah saya singkirkan adalah peluncur aplikasi. Terutama karena saya tidak memiliki pemahaman yang tepat tentang cara kerja peluncur aplikasi / apa yang mereka lakukan. Bahkan pencarian internet yang luas hanya menunjukkan penjelasan yang tidak jelas. Yang ingin saya lakukan adalah menyingkirkan bahkan peluncur aplikasi saya karena selain benar-benar menelurkan aplikasi saya sama sekali tidak menggunakannya. Untuk melakukan ini, saya benar-benar ingin tahu cara "benar" memulai aplikasi dari shell. Dimana arti dari "dengan benar" dapat didekati dengan "seperti yang dilakukan peluncur aplikasi".

Saya tahu tentang cara-cara berikut untuk menelurkan proses dari shell:

  1. exec /path/to/Program ganti shell dengan perintah yang ditentukan tanpa membuat proses baru
  2. sh -c /path/to/Program meluncurkan proses tergantung shell
  3. /path/to/Program meluncurkan proses tergantung shell
  4. /path/to/Program 2>&1 & luncurkan proses mandiri shell
  5. nohup /path/to/Program & meluncurkan proses mandiri shell dan mengarahkan ulang output ke nohup.out

Pembaruan 1: Saya dapat mengilustrasikan misalnya apa dmenumerekonstruksi dari panggilan berulang ke ps -efldalam kondisi yang berbeda. Ini memunculkan shell baru /bin/bashdan sebagai anak aplikasi ini shell /path/to/Program. Selama anak itu ada, maka kulitnya akan ada. (Bagaimana mengelola ini di luar saya ...) Sebaliknya jika Anda mengeluarkan nohup /path/to/Program &dari shell /bin/bashmaka program akan menjadi anak dari shell ini TETAPI jika Anda keluar dari shell ini induk program akan menjadi proses paling atas. Jadi jika proses pertama adalah eg /sbin/init verbosedan telah PPID 1maka itu akan menjadi induk program. Inilah yang saya coba jelaskan menggunakan grafik: chromiumdiluncurkan via dmenu, firefoxdiluncurkan menggunakan 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

Pembaruan 2: Saya kira pertanyaannya juga dapat dirubah menjadi: Apa yang seharusnya menjadi induk dari suatu proses? Haruskah misalnya menjadi shell atau haruskah initproses yaitu proses dengan PID 1?

Tuan. Sampah
sumber
3
Jawaban singkat untuk pertanyaan Anda adalah "apa pun yang mendapatkan hasil yang Anda inginkan."
Wayne Werner
1
dang, sampah - Anda mengajukan beberapa pertanyaan bagus. tapi saya pikir wayne ada di sini - suntingan terbaru Anda bertanya tentang init- yang jawabannya mungkin ... mungkin? itu tergantung pada bagaimana / jika Anda berencana untuk berbicara dengannya, apa yang initAnda gunakan, dan di mana saluran data berada. Secara umum hal-hal itu akan cenderung bekerja dengan sendirinya - itulah gunanya init. Dalam kasus apa pun, biasanya ketika Anda melakukan daemonisasi suatu proses init. Atau jika Anda ingin kontrol pekerjaan, shell saat ini.
mikeserv
Hahaha, tepuk tangan @mikeserv; 4:37 pagi di sini dan sudah menjadi tawa pertama hari itu. Benar, hal itu selalu berhasil. Saya akan menghapus dmenudan melihat bagaimana saya cocok dengan apa yang saya pelajari. Saya menemukan exec /path/to/Program & exitatau /bin/bash -c /path/to/Program & exitcukup berguna. Tapi mereka semua make 1yaitu initinduk dari Programyang baik-baik saja dengan saya selama ini masuk akal dan tidak melanggar dasar *nixprinsip-prinsip.
lord.garbage
@ lord.garbage - itu karena Anda exec &, saya pikir. Saya biasanya hanya melakukan barang-barang saya dari terminal ... mungkin Anda akan menggunakan pertanyaan ben crowell di sini . Saya punya jawaban di sana, tetapi semuanya sangat bagus. Lagi pula, ketika Anda melatar belakangi suatu proses dan orangtuanya mati seperti: sh -c 'cat & kill $$'Anda menjadi yatim piatu, dan akhirnya akan menuai akhirnya. itu pekerjaan init - itu sebabnya mereka semua jatuh ke dalamnya.
mikeserv
Mungkin pertanyaan sederhana untuk saat ini adalah: Bagaimana mungkin untuk mendapatkan pohon proses di atas dari shell: systemd--bash--chromium. Semua metode yang saya coba pada akhirnya akan mengarah ke pohon proses dari bentuk berikut systemd--chromiumketika saya menelurkan firefox dari shell. Bagaimana cangkang ini di iblis di sini? Itu tidak terkait dengan terminal apa pun.
lord.garbage

Jawaban:

7

Sepertinya Anda memiliki pemahaman yang cukup bagus tentang itu. Untuk memperjelas beberapa yang Anda miliki,

  • sh -c /path/to/Program cukup mirip dengan

    $ sh 
    % / path / to / Program 
    % Ctrl+ D                             (atau Anda dapat mengetik " keluar ") 
    $

    tempat Anda memulai proses shell baru, berikan jalur perintah aplikasi ke shell baru, dan kemudian biarkan shell baru berakhir. Saya telah menunjukkan shell baru memberikan prompt yang berbeda untuk tujuan ilustrasi; ini mungkin tidak akan terjadi dalam kehidupan nyata. The membangun sebagian besar berguna untuk melakukan hal-hal yang rumit, seperti membungkus beberapa perintah ke dalam sebuah kemasan, sehingga mereka terlihat seperti satu perintah (semacam script yang tidak disebutkan namanya sekali pakai), atau bangunan yang rumit perintah, mungkin dari variabel shell. Anda tidak akan pernah menggunakannya hanya untuk menjalankan satu program dengan argumen sederhana.sh -c "command"

  • 2>&1berarti mengarahkan kesalahan standar ke output standar. Ini tidak benar-benar ada hubungannya dengan &; alih-alih, Anda menggunakannya ketika perintah mengirim pesan kesalahan ke layar meskipun Anda mengatakan dan ingin menangkap pesan kesalahan dalam file.command > file
  • Mengarahkan output ke nohup.outadalah efek samping sepele dari nohup. Tujuan utama adalah untuk menjalankan secara tidak sinkron (umumnya dikenal sebagai "di latar belakang", atau sebagai "proses mandiri shell", untuk menggunakan kata-kata Anda) dan mengkonfigurasinya sehingga memiliki peluang yang lebih baik untuk dapat terus berjalan jika Anda menghentikan shell (mis., logout) saat perintah masih berjalan.nohup command &command

bash(1)dan Bash Reference Manual adalah sumber informasi yang bagus.

G-Man Mengatakan 'Reinstate Monica'
sumber
7

Ada beberapa cara untuk menjalankan program dan melepaskannya dari terminal. Pertama adalah menjalankannya di latar subkulit , seperti ini (ganti firefoxdengan program favorit Anda):

(firefox &)

Cara lain adalah menolak proses:

firefox & disown firefox

Jika Anda ingin tahu tentang bagaimana peluncur aplikasi kerja, dmenumenyediakan 1 biner dan 2 shell script: dmenu, dmenu_pathdan dmenu_runmasing-masing.

dmenu_rundmenu_pathmem -pipe output ke dalam dmenu, yang pada gilirannya pipa menjadi apa pun $SHELLvariabel Anda diatur. Jika kosong, itu akan digunakan /bin/sh.

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

dmenu_pathsedikit lebih rumit, tetapi singkatnya menyediakan daftar binari dalam $PATHvariabel lingkungan Anda , dan menggunakan cache jika memungkinkan.

#!/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

Tidak perlu menjalankan program dalam shell. Cara lain untuk menulis dmenu_run, tanpa menyalurkan ke shell adalah:

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

Saya suka jawaban G-Man. Tetapi saya merespons karena saya pikir Anda memiliki masalah yang membingungkan. Seperti yang ditunjukkan Wayne, jawaban terbaik adalah "apa pun yang mendapatkan hasil yang Anda inginkan".

Dalam manajemen proses Unix, setiap proses memiliki orang tua. Satu-satunya pengecualian untuk ini adalah initproses yang dimulai oleh OS saat boot. Ini adalah perilaku normal untuk proses induk untuk mengambil semua proses anak itu dengan itu ketika mati. Ini dilakukan dengan mengirimkan sinyal SIGHUP ke semua proses anak; penanganan default SIGHUP menghentikan proses.

Pemijahan shell dari proses pengguna tidak berbeda dengan jika Anda mengkodekan panggilan fork (2) / exec (3) dalam bahasa pilihan Anda. Shell adalah orang tua Anda, dan jika shell berakhir (misalnya, Anda log off), maka child process akan muncul. Nuansa yang Anda gambarkan hanyalah cara memodifikasi perilaku itu.

exec /path/to/programseperti memanggil exec (3) . Ya, itu akan mengganti shell Anda dengan program, menjaga induk apa pun meluncurkan shell.

sh -c /path/to/programsemacam tanpa tujuan membuat proses shell anak yang akan membuat proses anak program. Ini hanya bernilai jika /path/to/programsebenarnya merupakan urutan instruksi skrip, dan bukan file yang dapat dieksekusi. ( sh /path/to/script.shdapat digunakan untuk menjalankan skrip shell yang tidak memiliki izin eksekusi di shell yang lebih rendah)

/path/to/programmenciptakan proses "foreground", yang berarti bahwa shell menunggu proses untuk menyelesaikan sebelum mengambil tindakan lain. Dalam konteks system call, itu seperti fork (2) / exec (3) / waitpid (2) . Perhatikan bahwa anak mewarisi stdin / stdout / stderr dari orang tua.

/path/to/program &(mengabaikan pengalihan) menciptakan "proses latar belakang". Prosesnya masih anak-anak dari shell, tetapi orang tua tidak menunggu untuk mengakhiri.

nohup /path/to/programmeminta nohup (1) untuk mencegah pengiriman SIGHUP programjika terminal pengendali ditutup. Apakah itu di latar depan atau latar belakang adalah pilihan (meskipun paling umum prosesnya adalah latar belakang). Perhatikan bahwa nohup.outhanya output jika Anda tidak mengarahkan stdout.

Saat Anda meletakkan proses di latar belakang, jika proses induk mati, salah satu dari dua hal terjadi. Jika orang tua adalah terminal pengendali , maka SIGHUP akan dikirim ke anak-anak. Jika tidak, maka prosesnya mungkin "yatim piatu", dan diwarisi oleh initproses tersebut.

Ketika Anda mengarahkan input / output / kesalahan, Anda cukup menghubungkan deskriptor file yang setiap proses memiliki file yang berbeda dari yang diwarisi dari induknya. Tidak satu pun dari ini yang mempengaruhi kepemilikan proses atau kedalaman pohon (tetapi selalu masuk akal untuk mengarahkan semua 3 jauh dari terminal untuk proses latar belakang).

Dengan semua yang dikatakan, saya tidak berpikir Anda harus peduli dengan pembuatan proses oleh shell atau sub-shell atau sub-proses, kecuali ada masalah khusus yang Anda atasi terkait dengan manajemen proses.

jwm
sumber
nitpick: sh -c /path/to/programtidak akan menjalankan program sebagai skrip shell jika tidak ada bit yang dapat dieksekusi sh /path/to/program. sh -c /path/to/programhanya akan membuka shell dan menjalankan /path/to/programsebagai perintah di shell itu, yang akan gagal jika itu tidak dapat dieksekusi.
filbranden
Nah, jika kita melakukan nitpicking, kita berdua salah. sh -c /path/to/programmembaca perintah dari /path/to/programsebagai input ke shell. Itu tidak mengharuskan file tersebut memiliki izin mengeksekusi tetapi itu harus skrip shell
jwm
Hmmm, sh /path/to/programlakukan itu. Coba saja sendiri :, echo echo hello world >abc.shlalu sh ./abc.shcetak hello world, sambil sh -c ./abc.shberkata sh: ./abc.sh: Permission denied(yang sama seperti jika Anda akan menjalankan ./abc.shshell saat ini secara langsung.) Apakah saya melewatkan sesuatu? (Atau mungkin saya tidak mengekspresikan diri dengan baik di komentar sebelumnya ...)
filbranden
Salahku. sh -c _something_sama dengan hanya mengetik _something_di prompt perintah, kecuali untuk pemijahan shell inferior. Jadi Anda benar bahwa itu akan gagal jika melewatkan bit eksekusi (sebagai file). Di sisi lain, Anda dapat memberikan serangkaian perintah shell seperti sh -c "echo hello world"dan itu akan berfungsi dengan baik. Jadi itu tidak mengharuskan apa yang Anda ketik memiliki bit eksekusi (atau bahkan menjadi file), hanya saja shell interpreter dapat melakukan sesuatu dengannya.
jwm
Saya percaya OP mengacu pada beberapa yang dikompilasi atau sistem yang dapat dieksekusi, jadi izin eksekusi diasumsikan.
jwm