Вийдіть з терміналу після запуску bash-скрипту


18

Я намагаюся написати bashсценарій для відкриття певних файлів (переважно файлів у форматі PDF) за допомогою gnome-openкоманди. Я також хочу, щоб термінал вийшов, як тільки він відкриє файл pdf.

Я намагався додати exitдо кінця свого сценарію, однак це не закриває термінал. Я намагався шукати відповідь на моє запитання в Інтернеті, але я не зміг знайти належного, я дуже вдячний, якщо ви, хлопці, зможете допомогти.

Мені потрібна відповідь, що тільки вбиває термінал, з якого я запускаю команду, чи не всі термінали це можливо? Попередня відповідь, яку я прийняв, вбиває всі відкриті вікна терміналів. Я не усвідомлював, що це було так до сьогодні.


Ви запускаєте сценарій в терміналі в першу чергу? Суворо з командного рядка немає ніяких причин відкривати термінал для цього.
Яків Влійм

Так, я запускаю скрипт з терміналу. Я не здогадувався про різницю між терміналом і командним рядком
Румеш

Я замінив gnome-openз xdg-openв моєму сценарії , але немає ніяких змін. Термінал як і раніше залишається відкритим
Румеш

@Tim Wow, це працює =) +1
AB

@Tim Але і моє рішення не було поганим. ;)
AB

Відповіді:


12

Якщо ви відкриваєте тільки один файл, ви не дійсно потрібно використовувати сценарій, тому що сценарій призначається , щоб бути простий спосіб запустити кілька команд поспіль, а тут просто потрібно запустити дві команди ( в тому числі exit) .

Якщо ви хочете запустити exitпісля команди або після ланцюжка команд, ви можете зв'язати її з тим, що вже є, скориставшись &&оператором (який після успіху попередньої команди / ланцюжок команд виконає наступну команду) або за допомогою ;оператор (який як при успіху, так і при відмові попередньої команди / ланцюжка команд виконає наступну команду).

У цьому випадку це було б щось подібне:

gnome-open <path_to_pdf_file> && exit

* <path_to_pfd_file> = шлях до pdf-файлу

exitставити в кінці сценарію не працює, тому що він просто закриває bashекземпляр, в якому запускається сценарій, що є іншим bashекземпляром, ніж внутрішній bashекземпляр термінала .

Якщо ви хочете все-таки використовувати скрипт, найпростіший спосіб - просто викликати сценарій так:

<path_to_script> && exit

Або якщо сценарій знаходиться в поточному робочому каталозі терміналу так:

./<script> && exit

Якщо ви дійсно не хочете / не можете цього зробити, другий найпростіший спосіб - додати цей рядок у кінці сценарію:

kill -9 $PPID

Це відправить SIGKILLсигнал на батьківський процес сценарію ( bashекземпляр, пов'язаний з Терміналом). Якщо bashдо Терміналу пов'язаний лише один екземпляр, то вбивство призведе до закриття Терміналу. Якщо bashдо Терміналу пов’язано кілька примірників, вбивство не призведе до того, що Термінал закриється.


2
Сигнал SIGTERM надсилається процесу з вимогою його припинення. На відміну від сигналу SIGKILL, його можна вловлювати та інтерпретувати або ігнорувати в процесі. Це дозволяє процесу виконувати гарне припинення, вивільняючи ресурси та зберігаючи стан, якщо це доречно. SIGINT майже ідентичний SIGTERM.
AB

@AB Ви маєте рацію, SIGTERMтут недостатньо.
кос

Дякую за відповідь. Я думаю, що погано використовувати єдину команду, яку ви дали у своїй відповіді
Румеш

kill $ PPID робить те саме, що і вихід - нічого. І знищити -9 $ PPID закриє всі дочірні вікна разом з батьком.
SDsolar

5

Цей сценарій припиняє термінал і, таким чином, оболонку і себе.

Це нещадно вбиває всі процеси. Якщо в терміналі відкрито кілька вкладок, вони також закриті.

Проблема полягає в тому, що якщо відкрити кілька терміналів і це дочірні процеси gnome-terminal-server, усі термінали будуть вбиті.

У цьому випадку сценарій слід запустити в незалежному терміналі, наприклад xterm

<your_command> & disown

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

    PPID - це батьківський ідентифікатор процесу, у цьому випадку shell ( e.g. /bin/bash)

  • PPPID

    PPPID - це батьківський ідентифікатор процесу PPID, у цьому випадку - вікно терміналу

  • <your_command> & disown

    У команді bash команда disown вбудована використовується для видалення завдань із таблиці завдань або для позначення завдань, щоб сигнал SIGHUP не надсилався їм, якщо батьківська оболонка отримує його (наприклад, якщо користувач виходить із системи).

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

    Отримує значення четвертого стовпця файла /proc/$PPID/stat(наприклад, /proc/1/statвін повертає 0)


Я думаю, що команда $$ get - це піде термінал ... Це було б альтернативою? Не могли б ви пояснити, як відмовитися?
Тим

Як це робить цей сценарій? Я все ще новачок в сценарії оболонок, тому не можу реально зрозуміти ці команди. Поясніть, будь ласка, як він закриває термінал
Румеш

1
@Tim Ні, він повертає оболонку в терміналі: ps xa | grep $$=> 4381 pts/0 Ss 0:01 /usr/bin/zsh
AB

1
@RumeshSudhaharan Це вбиває все вікно терміналу, в якому запускається сценарій, але ніяких інших вікон терміналів.
AB

3
@AB Ви раніше говорили, що це вбиває лише поточне вікно терміналу, а не будь-яке інше. Я використовував цей скрипт сьогодні з відкритими двома термінальними вікнами, і обидва вони були вбиті, коли я запустив сценарій.
Румеш

4

Можна використовувати .exec ./your-script

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

Якщо ви вже перебуваєте в терміналі і єдине, що ви хочете зробити перед тим, як вийти з цього терміналу, - це запустити певний скрипт (або програму), то це означає, що вам більше не потрібна оболонка, яка працює в ньому. Таким чином, ви можете використовувати execвбудований оболонку, щоб змусити оболонку замінити себе процесом, створеним вашою командою.

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

Синтаксис , наприклад, .exec commandexec ./your-script

exec: приклад

Наприклад, припустимо, що у мене є скрипт оболонки, який називається count, позначений виконуваним і розміщений у поточному каталозі. Це містить:

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

І в терміналі я запускаю:

exec ./count

Це друкує цифри 5, 4, 3, 2, і 1, по одному на кожну секунду, а потім вікно закривається термінал.

Якщо ви запускаєте це з чогось іншого, ніж перший запуск процесу у вашому терміналі - наприклад, якщо ви запустили bashперший, щоб запустити інший екземпляр оболонки - то це поверне вас до оболонки, яка створила цей процес, а не виходу з терміналу. (Цей застереження застосовується однаково до exitметодів, заснованих на основі.)

Можна використовувати ../your-script; exit

Якщо ви не хочете казати своїй оболонці замінювати себе новим процесом (через exec), ви можете сказати, щоб він тримався, але вийшов із себе відразу після завершення нового процесу.

Для цього запустіть свою команду та exitкоманду, розділену ;так, щоб їх можна було задати в одному рядку.

Синтаксис command; exit, наприклад, ../your-script; exit

command; exit vs. command && exit

Ви можете помітити , це виглядає так само, метод , запропонований в Kos ігрових і heemayl - х відповіді. Різниця полягає в тому, що:./your-script && exit

  • &&запускає другу команду лише в тому випадку, якщо перша команда повідомила, що це вдалося , повернувши вихідний нуль.
  • ; виконує другу команду незалежно від того, чи не повідомила перша команда про успіх.

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

Є також command || exit, яка закриває оболонку виклику, лише якщо commandповідомила про помилку .


2

Ви можете джерелом сценарію замість запуску, наприклад

$ cat run.sh
exit;
$ ./run.sh #will not close
$ . ./run.sh # will close

1

Особисто я виконав би команду відкрити pdf чи інші файли в підрозділі, поставив затримку, щоб відкрити файли, а потім вийти. В основному, ось що я перевірив(nohup gnome-open *.pdf &); sleep 2; exit

Варіант щодо цього був би nohup gnome-open *.pdf && sleep 2 && exit


У моєму випадку, оскільки nohupігнорує сигнал зависання, nohup xdg-open some_programпрацював на мене і exitбув непотрібним. nohupповідомлення про переадресацію до nohup.outфайлу:nohup: ignoring input and appending output to nohup.out
nick indiessance

0

Найпростішим рішенням було б:

xdg-open file.pdf && exit

На відміну від інших подібних команд nohupне потрібно, щоб ігнорувати команду SIGHUP, причиною цього xdg-openбуде вихід нересту дочірнього процесу, який є кращим додатком для відкриття файлу pdf. Оскільки фактичний процес, розпочатий з терміналу, вже не вбивати, nohupне потрібен.

&&вказує, що наступна команда буде запущена, якщо попередня команда успішна, тобто повертає код виходу 0( $?=0) і exitпросто закриє термінал.


Я думаю, що він сказав, що вихід не працює ...
Тім

@Tim: Можливо, ОП не використовував це правильно, з питання, яке мені дуже незрозуміло, як він / вона поставив її exitв кінці і не працював ..
heemayl

1
@Tim Тому що OP поміщений exitвсередині скрипту, який є невикористаним, оскільки він має ефект виходу із bashекземпляра, в якому виконується сценарій, а не батьківського bashекземпляра (той, що пов'язаний з Терміналом), що призведе до того, що Термінал замість цього закриється
kos

1
У будь-якому випадку xdg-openпрацює вже у фоновому режимі і від’єднано від Терміналу, тому вам тут не потрібно nohup, плюс з того, що я розумію, OP працює xdg-openкілька разів всередині сценарію, щоб відкрити пакетні декілька файлів, використовуючи, xdg-openяк, що всередині сценарію, це спричинить сценарій вийти при першій xdg-openподії
kos

@kos: Ні, я не біг xdg-openв backgr, навіть якщо я мав nohupце з іншої причини і повинна бути there..any фонового процесу від ініціюючого терміналу буде убитий , коли ви вб'єте батьківський термінал .. nohupє , щоб запобігти це .. як мені не потрібно знову використовувати термінал інтерактивно, немає необхідності вводити процес у bg..on вашу 2-ю точку, яку також можна запобігти, запустивши кожного xdg-open && exitв
нижній частині

0

Щоб чітко відповісти на заголовкове запитання,

"Вийти з терміналу після запуску bash script" :

Запустити лише свій сценарій у терміналі

Не дивлячись на деталі, що робить сценарій, сценарій можна запустити безпосередньо в терміналі з опцією -e( --command), не запускаючи оболонку - він використовується замість оболонки тоді:

gnome-terminal -e ./script.sh

Використовуйте параметр -x( --execute), коли ви хочете надати аргументи сценарію. При цьому просто весь залишок командного рядка приймається за команду та аргументи.

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

Якщо ваш скрипт виходить, немає інтерактивної оболонки, яка могла б затримати що-небудь, чекаючи введення користувача.

Приклади

Темінал вийде лише після того, як команда, що працює в ньому, завершиться - ось так, закриття після sleepзапуску 4 секунди, без оболонки:

gnome-terminal -x sleep 4

Звичайно, ви можете використовувати сценарій оболонки, оскільки ваш сценарій у будь-якому випадку використовує інший екземпляр оболонки.

Також ви можете запустити оболонку з явним сценарієм - вона не буде інтерактивною:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.