Як "правильно" запустити програму з оболонки


21

Мені важко точно сформулювати це питання, але я дам все можливе. Я використовую dwmв якості менеджера вікон за замовчуванням іdmenuяк мій запуск програми. Я навряд чи використовую програми GUI окрім свого браузера. Більшість моєї роботи виконується безпосередньо з командного рядка. Крім того, я великий прихильник мінімалізму щодо операційних систем, додатків тощо. Одним із інструментів, від якого я ніколи не позбувся, був запуск програми. Головним чином тому, що мені не вистачає точного розуміння того, як працюють пускові програми / що вони роблять. Навіть розширений пошук в Інтернеті виявляє лише розпливчасте пояснення. Що я хочу зробити, це позбутися навіть моєї програми запуску програм, тому що, крім фактично нерестуючої програми, я абсолютно не користуюся цим. Для цього мені дуже хочеться знати, як "правильно" запустити програми з оболонки. При цьому значення "правильно" можна наблизити до ", як це зробить запуск програми".

Мені відомо про такі способи нерестування процесів із оболонки:

  1. exec /path/to/Program замініть оболонку вказаною командою без створення нового процесу
  2. sh -c /path/to/Program запустити залежний від оболонки процес
  3. /path/to/Program запустити залежний від оболонки процес
  4. /path/to/Program 2>&1 & запуск незалежної оболонки
  5. nohup /path/to/Program & запустити незалежний процес оболонки і перенаправити вихід на nohup.out

Оновлення 1: Я можу проілюструвати, що наприклад dmenuреконструює його від повторних дзвінків до ps -eflрізних умов. Він породжує нову оболонку /bin/bashі як дитина цієї оболонки додаток /path/to/Program. Поки дитина довкола, так довга буде оболонка. (Як це управляє, це не в мене ...) На відміну від того, якщо ви випустите nohup /path/to/Program &з оболонки, /bin/bashпрограма стане дочірньою оболонкою, АЛЕ якщо ви вийдете з цієї оболонки, то батьківський програмою буде найвищий процес. Отже, якщо перший процес був, наприклад, /sbin/init verboseі він є, PPID 1то він буде батьківською програмою. Ось що я спробував пояснити за допомогою графіка: chromiumзапускався через dmenu, firefoxзапускався за допомогою 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

Оновлення 2: Я думаю, що питання також може бути зведено до: Що має бути батьківським процесом? Якщо це, наприклад, оболонка, чи це initпроцес, тобто процес з PID 1?


3
Лаконічною відповіддю на ваше запитання буде "все, що отримає бажані результати".
Уейн Вернер

1
бовтатися, сміття - ви задаєте кілька хороших питань. але я думаю, що Уейн тут на носі - запитує ваша остання редакція init- на що відповідь може бути ... можливо? це залежить від того, як / якщо ви плануєте поговорити з ним, чим initви користуєтесь та де канали даних. Взагалі, речі, як правило, випрацьовуються - ось для чого init. У будь-якому випадку, як правило, коли ви демонізуєте процес init. Або якщо ви хочете контролювати роботу, поточну оболонку.
mikeserv

Хахаха, ура @mikeserv; 4:37 ранку тут і вже перший сміх за день. Щоправда, ця штука завжди якось виходить. Я зніму dmenuі побачу, як я ладжу з тим, що дізнався. Я вважаю, exec /path/to/Program & exitабо /bin/bash -c /path/to/Program & exitбути цілком корисним. Але всі вони мають сенс, 1тобто initбатько, Programякий зі мною добре, якщо це має сенс і не порушує жодних основних *nixпринципів.
lord.garbage

@ lord.garbage - це тому, що ти exec &, я думаю. Зазвичай я просто роблю свої речі з терміналу ... можливо, ви б тут скористалися питанням Бен Кроуелла . У мене є відповідь там, але всі вони дуже хороші. у будь-якому випадку, коли ви перебуваєте в фоновому режимі, і його батько помирає так: sh -c 'cat & kill $$'ви осиротіли його, і він закінчується, зрештою пожинаючи. це робота Ініта - саме тому вони всі до цього потрапляють.
mikeserv

Може бути, простіше питання зараз: як це можливо , щоб отримати вищевказане дерево процесів з оболонки: systemd--bash--chromium. Усі методи, які я спробую, в кінцевому підсумку призведуть до дерева технологічних процесів наступної форми, systemd--chromiumколи я породжую firefox з оболонки. Як тут демонізована шкаралупа? Він не пов'язаний з жодним терміналом.
lord.garbage

Відповіді:


7

Що ж, ти, здається, дуже добре розумієш це. Щоб уточнити, що у вас є,

  • sh -c /path/to/Program досить схожий на

    $ sh 
    % / шлях / до / Програма 
    % Ctrl+ D                             (або ви можете ввести " вихід ") 
    $

    де ви запускаєте новий процес оболонки, введіть шлях команди до нової оболонки, а потім дозвольте завершенню нової оболонки. Я показав нову оболонку, яка дає іншу підказку для цілей ілюстрації; це, мабуть, не відбудеться в реальному житті. Конструкція в основному використовується для виконання хитрих речей, як упаковка кілька команд в одній зв'язку, так що вони виглядають як єдина команда (на кшталт одноразового безіменного сценарію), або будівлі , складні команд, можливо , від оболонки змінних. Ви навряд чи коли-небудь використовувати його лише для запуску однієї програми з простими аргументами.sh -c "command"

  • 2>&1означає перенаправити стандартну помилку на стандартний вихід. Це насправді не має великого стосунку &; скоріше, ви використовуєте його, коли команда надсилає повідомлення про помилки на екран, навіть якщо ви говорите і хочете зафіксувати повідомлення про помилку у файлі.command > file
  • Перенаправлення виводу на nohup.outтривіальний побічний ефект nohup. Основна мета - запустити асинхронно (загально відомий як "у фоновому режимі" або як "незалежний від оболонки процес", використовувати ваші слова) та налаштувати його, щоб мати більше шансів на можливість продовжувати працювати, якщо ви завершіть оболонку (наприклад, вихід із системи), поки команда ще працює.nohup command &command

bash(1)та Довідковий посібник Баша є хорошими джерелами інформації.


7

Існує кілька способів виконання програми та від'єднання її від терміналу. Перший - запустити його у фоновому режимі передплатки , як це (замінити firefoxулюбленою програмою):

(firefox &)

Інше - відмовитися від процесу:

firefox & disown firefox

Якщо ви хочете знати , як додаток пускові роботи, dmenuзабезпечує 1 двійковий і 2 сценарії оболонки: dmenu, dmenu_pathі dmenu_run, відповідно.

dmenu_runпередає вихід dmenu_pathу dmenu, що в свою чергу перетворює на будь-яку $SHELLзміну. Якщо він порожній, він використовуватиме /bin/sh.

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

dmenu_pathє трохи складнішим, але, коротко кажучи, він пропонує список бінарних файлів у $PATHзмінній вашого середовища, а також використовує кеш, якщо це можливо.

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

Не обов’язково, щоб програми працювали в оболонках. Ще один спосіб запису dmenu_run, не вкладаючи в оболонку, буде:

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

6

Мені дуже подобається відповідь G-Man. Але я відповідаю, бо думаю, що ви бентежите занепокоєння. Як вказує Уейн, найкраща відповідь - "все, що отримує потрібні результати".

В управлінні процесами Unix кожен процес має батьківського. Винятком з цього є initпроцес, який запускається ОС під час завантаження. Це нормальна поведінка для батьківського процесу, коли він помирає з усіма своїми дочірніми процесами. Це робиться шляхом надсилання сигналу SIGHUP до всіх дочірніх процесів; обробка SIGHUP за замовчуванням припиняє процес.

Нерестові оболонки користувальницьких процесів не відрізняються, ніж якщо ви кодували виклики fork (2) / exec (3) на обраній вами мові. Оболонка - це ваш батько, і якщо оболонка закінчується (наприклад, ви виходите з системи), тоді дочірній процес (і), який вона породжує, йде разом із нею. Ви описані нюанси - це лише способи зміни такої поведінки.

exec /path/to/programце як викликати exec (3) . Так, він замінить вашу оболонку program, зберігаючи незалежно від того, хто з батьків запустив оболонку.

sh -c /path/to/programвид безглуздо створює процес дитячої оболонки, який створить дочірній процес program. Він цінний лише, якщо /path/to/programнасправді є послідовністю інструкцій сценарію, а не виконуваним файлом. ( sh /path/to/script.shможе використовуватися для запуску сценарію оболонки, у якому відсутні дозволи на виконання в нижчій оболонці)

/path/to/programстворює процес "переднього плану", тобто оболонка чекає завершення процесу перед тим, як здійснити будь-які інші дії. У контексті системного виклику це як fork (2) / exec (3) / waitpid (2) . Зауважте, що дитина успадковує stdin / stdout / stderr від батьків.

/path/to/program &(ігнорування перенаправлення) створює "фоновий процес". Процес все ще є дочірньою оболонкою, але батько не чекає її припинення.

nohup /path/to/programвикликає nohup (1) для запобігання надсилання SIGHUP, programякщо контрольний термінал закритий. Вибір на передньому плані чи фон - це вибір (хоча найчастіше процес є фоновим). Зверніть увагу, що nohup.outце лише вихід, якщо іншим чином ви не перенаправляєте stdout.

Коли ви ставите процес на задній план, якщо батьківський процес помирає, відбувається одна з двох речей. Якщо батько є керуючим терміналом , тоді SIGHUP буде направлений дітям. Якщо це не так, то процес може бути «осиротілим» і передається у спадок від initпроцесу.

Коли ви переспрямовуєте введення / виведення / помилку, ви просто підключаєте дескриптори файлів, які кожен процес має до різних файлів, ніж ті, які він успадковує від свого батьківського. Ніщо з цього не впливає на право власності на процес чи глибину дерева (але завжди має сенс перенаправляти всі 3 від терміналу для фонових процесів).

З урахуванням сказаного, я не думаю, що вам слід займатися створенням процесів оболонкою або підшарпами або підпроцесами, якщо не виникає конкретна проблема, з якою ви вирішуєте питання управління процесом.


nitpick: sh -c /path/to/programне запустить програму як скрипт оболонки, якщо в ній відсутні файли, що виконуються, sh /path/to/programбуде. sh -c /path/to/programпросто відкриє оболонку і запуститься /path/to/programяк команда в цій оболонці, яка вийде з ладу, якщо вона не виконується.
filbranden

Що ж, якщо ми забираємо думки, ми обидва помиляємося. sh -c /path/to/programчитає команди з /path/to/programвведення в оболонку. Тут не потрібно, щоб файл мав дозвіл на виконання файлу, але це повинен бути сценарій оболонки
jwm

Гммм, sh /path/to/programчи так. Я просто спробував це:, echo echo hello world >abc.shпотім sh ./abc.shдрукує hello world, тоді як sh -c ./abc.shкаже sh: ./abc.sh: Permission denied(що таке саме, як якщо б ти запустив безпосередньо ./abc.shв поточній оболонці.) Я щось пропустив? (А може, я не висловив себе добре в попередньому коментарі ...)
filbranden

Моя провина. sh -c _something_те саме, що просто набрати _something_в командному рядку, за винятком нересту нижчої оболонки. Отже, ви праві, що він не вдасться, якщо не вистачить біт виконання (як файл). З іншого боку, ви можете надати ряд команд оболонки, як, sh -c "echo hello world"і це буде добре працювати. Тому не потрібно, щоб те, що ви вводите, мати біт виконання (або навіть бути файлом), лише щоб інтерпретатор оболонки міг щось робити з ним.
jwm

Я вважаю, що ОП посилався на якийсь компільований або виконаний у системі файл, тому дозвіл на виконання передбачався.
jwm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.