Убейте текущую оболочку bash и запустите новую с некоторой командой.

Вопрос или проблема

можно ли убить/выйти из текущего bash шелла и запустить новый с помощью какой-то команды? Такое как

kill -9 $PPID && bash -c echo 'I started new!'

что, очевидно, не работает.

Конечно. Как только вы входите в систему, введите “bash”, чтобы открыть новый шелл поверх вашего логина.

Затем делайте все, что вы хотите, в той шелл-среде.

Когда вы будете готовы убить это и начать “с чистого листа” в новом шелле, просто введите “exit”, а потом снова “bash”.

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

Запуск процесса осуществляется клонированием (форканием) его.

Запуск команды будет означать ее выполнение.

Что-то обычно запускает скрипт шелла (например, bash) путем форкания себя, и в одной из ветвей форка (обычно в дочернем процессе) выполняется execve("/path/to/bash", ["bash", "/path/to/the-script"], environ).

Этот процесс будет читать содержимое the-script по одной строке за раз и интерпретировать код шелла в нем.

Перед этим он инициализирует несколько специальных параметров, включая $$ для pid процесса, который его выполнил, $PPID для родительского процесса (на тот момент; это может быть другая ветвь вышеуказанного форка или pid 1 или дочерний subreaper).

Некоторые из прочитанного кода часто заставляют процесс шелла порождать больше процессов (форкануть себя), в некоторых из которых он будет выполнять больше команд. Ведь шелл — это интерпретатор языка, специализированный на выполнение команд, и их нужно запускать в отдельных процессах, если вы хотите выполнить более одной команды.

Для тех команд, которые являются встроенными в шелл, такими как kill, шеллу не нужно делать форк для их выполнения.

Стоит отметить, что в этих дочерних процессах $$ и $PPID остаются неизменными, независимо от того, все ли еще соответствующие процессы живы или нет. Это не pid и ppid шелла, который, случайно, расширяет эти параметры, это pid и ppid процесса, который изначально запустил интерпретатор шелла.

Так что, когда вы делаете kill -9 $PPID, это (при условии, что $IFS не был изменен, так как вы забыли заключить это расширение в кавычки) выполнит команду kill в том же процессе, который может быть или не быть тем, который изначально запустил шелл (если этот код найден в subshell или pipeline, например), и отправит сигнал SIGKILL (сигнал, который нельзя обработать и должен использоваться только как крайняя мера) процессу-родителю, от процесса, который запустил шелл в момент его инициализации.

Это не убьет шелл, хотя шелл может умереть как следствие смерти своего родителя. Например, если родитель — это эмулятор терминала, процесс(ы) шелла могут получить SIGHUP, когда терминал закроется.

Если вы замените это на kill "$$", тогда процесс, который изначально запустил шелл как дочерний процесс и который может все еще ожидать завершения этого процесса, увидит, что тот умер, и продолжит свои дела.

Если это процесс с pid равным $$, который выполнил kill "$$", тогда он умрет и не сможет продолжить bash -c echo 'I started new!'.

Что вы можете сделать здесь, так это:

exec bash -c echo 'I started new!'

exec скорее нужно было бы назвать no-fork. Это говорит текущему процессу шелла выполнить bash в том же процессе, а не в дочернем, так что, по сути, это перезапустит шелл, переисполнит его в том же процессе. Этот процесс не завершится. Если у него все еще есть родитель, ожидающий его, то этот родитель не увидит его конец, пока новый шелл bash не вызовет exit или не будет убит.

Вы также можете сделать:

bash -c echo 'I started new!' & exit

В этом случае текущий процесс шелла запускает bash в качестве своего дочернего процесса, но не ждет его завершения и выходит сразу.

Затем, если у него есть родитель, он увидит, что процесс шелла завершается, но не будет знать о новом процессе bash (своем внуке).

Ответ или решение

Вопрос о том, как завершить текущий bash-скрипт и запустить новый с заданной командой, требует глубокого понимания работы процессов и механизмов запуска команд в операционных системах на базе UNIX. В частности, он подразумевает правильное использование команд оболочки bash и возможных сценариев работы, таких как exec, fork и управление процессами. Рассмотрим это поэтапно, уделяя внимание теоретической основе, примерам и практическому применению.

Теория

В операционных системах типа UNIX, включая Linux, процессы представляют собой исполняемые единицы, которые создаются и контролируются ядром системы. Запуск нового процесса обычно осуществляется через системный вызов fork(), который создает копию текущего процесса, и execve(), который загружает в процесс новую программу. В случае с оболочкой bash, процессы используются для запуска командных интерпретаторов, скриптов и различных задач.

Специфическим элементом работы в bash является использование переменных среды $$ и $PPID. Переменная $$ обозначает ID текущего процесса оболочки (PID), а переменная $PPID – ID родительского процесса. Эти переменные и их значения критично важны при управлении процессами, так как именно через них идентифицируется и управляется текущая и родительская сессии.

Пример

Допустим, у вас есть задача завершить текущий сеанс оболочки и сразу запустить новый с выполнением конкретной команды. Неправильное использование kill по отношению к текущему процессу вызовет ситуацию, в которой текущая оболочка завершится прежде, чем новая будет запущена, нарушая ожидаемую последовательность.

Корректным решением может быть использование команды exec, которая позволяет заменить текущий процесс новым, не создавая дополнительных потомков. Рассмотрим использование команды exec:

exec bash -c "echo 'I started new!'"

Здесь exec запускает новую команду в текущем процессе вместо создания дочернего. Это значит, что текущий bash закончит своё выполнение, и вместо него начнёт выполняться bash -c "echo 'I started new!'", что и соответствует вашей задаче.

Применение

На практике это полезно в скриптах и сценариях автоматизации. Например, если скрипт требует "перезапуска" в тех же условиях, включая наследование всех файловых дескрипторов и переменных окружения, использование exec даёт возможность сделать это безопасно и согласованно.

Ещё один сценарий:

bash -c "echo 'I started new!'" & exit

Эта последовательность запускает новый процесс bash в фоновом режиме с командой и завершает текущий. Однако важно помнить, что в этом случае новый bash не наследует идентичного состояния по отношению к текущему процессу.

Заключение

Таким образом, способность управлять потоками выполнения через командную оболочку bash требует как теоретических знаний об операционной системе, так и практических навыков написания скриптов. Понимание, когда следует использовать fork, exec, или kill, как оперировать между процессами и как их контролировать, критически важно для успешной автоматизации и управления средой выполнения. Изложенные концепции не только обеспечивают более глубокое понимание работе bash-скриптов, но и помогают в эффективной разработке устойчивых и надёжных решений в области программирования и управления IT-системами.

Оцените материал
Добавить комментарий

Капча загружается...