Выход из терминала после запуска скрипта bash

18

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

Я попытался добавить exitв конец моего сценария, однако это не закрывает терминал. Я пытался найти в Интернете ответ на свой вопрос, но не смог найти подходящий, я был бы очень признателен, если бы вы, ребята, могли помочь.

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

Rumesh
источник
Вы запускаете скрипт в терминале? Строго из командной строки нет причин открывать терминал для этого.
Джейкоб Влейм
Да, я запускаю скрипт из терминала. Я не понимал, что есть разница между терминалом и командной строкой
Rumesh
Я заменил gnome-openс xdg-openв моем сценарии , но нет никаких изменений. Терминал по-прежнему открыт
Румеш
@ Тим Вау, это работает =) +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здесь недостаточно.
Кос
Спасибо за ответ. Я полагаю, плохо, я использую только одну команду, которую вы дали в своем ответе
Rumesh
kill $ PPID делает то же самое, что и exit - ничего. И kill -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)

AB
источник
Я думаю, что команда $$ get это pid терминала ... Это будет альтернативой? Не могли бы вы также объяснить, как отказаться?
Тим
Как этот скрипт делает это? Я все еще новичок в сценариях оболочки, поэтому я не могу понять эти команды. Не могли бы вы объяснить, как он закрывает терминал
Rumesh
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 Terminal, завершает работу, когда завершается начальный процесс, выполняющийся внутри него - обычно это оболочка.

Если вы уже находитесь в терминале, и единственное, что вы хотите сделать перед выходом из этого терминала, это запустить определенный скрипт (или программу), то это означает, что вам больше не нужна оболочка, которая в нем работает. Таким образом, вы можете использовать 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 против 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просто закроет терминал.

heemayl
источник
Я думаю, что он сказал, что выход не работает ...
Тим
@Tim: Возможно, OP не использовал его правильно, из-за вопроса, который мне очень непонятен, как он / она ставил exitв конце и не работал ..
Heemayl
1
@Tim Потому что OP помещают exitвнутрь скрипта, что бесполезно, потому что имеет эффект выхода из bashэкземпляра, в котором выполняется скрипт, а не из родительского bashэкземпляра (тот, который связан с терминалом), что приведет к закрытию терминала вместо
Кос
1
В любом случае, он xdg-openработает уже в фоновом режиме и не связан с терминалом, так что nohupздесь вам это не нужно , плюс, насколько я понимаю, OP запускается xdg-openнесколько раз внутри скрипта для пакетного открытия нескольких файлов, использование xdg-openэтого внутри скрипта вызовет скрипт чтобы выйти на первое xdg-openвстречаемости
кос
@kos: Нет, я не бег xdg-openв backgr, даже если я имел nohupэто по другой причине и должна быть there..any фонового процесса от инициирующего терминала будет убит , когда вы убьете родительский терминал .. nohupесть , чтобы предотвратить это ... поскольку мне не нужно снова использовать терминал в интерактивном режиме, нет необходимости помещать процесс в bg..на ваш второй пункт, который также можно предотвратить, запустив каждый xdg-open && exitв подоболочке ..
heemayl
0

Чтобы явно ответить на заглавный вопрос,

«Выход из терминала после запуска bash-скрипта» :

Запускай только свой скрипт в терминале

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

gnome-terminal -e ./script.sh

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

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

Если ваш скрипт завершается, нет никакой интерактивной оболочки, которая могла бы задержать что-либо, ожидая пользовательского ввода.

Примеры

Теминал просто выйдет после того, как выйдет запущенная в нем команда - вот так, закрытие после sleep4 секунд запуска без оболочки:

gnome-terminal -x sleep 4

Конечно, вы можете по-прежнему использовать сценарии оболочки, потому что в любом случае ваш сценарий использует другой экземпляр оболочки.

Кроме того, вы можете запустить оболочку с явным сценарием - она ​​не будет интерактивной:

gnome-terminal -x bash -c "echo 'Hello!'; sleep 4"
Volker Siegel
источник