Linux pid фонового процесса

Работа с процессами в Linux

Управление процессами является неотъемлемой частью администрирования серверных систем под управлением ОС Linux. В этой практической статье мы рассмотрим примеры решения различных задач по управлению процессами.

Вообще, процесс, как и файл является фундаментальной абстракцией ОС Linux. То есть, без процессов невозможно функционирование данной (как, впрочем, и любой другой) операционной системы.

В рамках данной статьи я не буду сильно погружаться в теорию и рассказывать о том как процессы взаимодействуют с операционной системой и пользователем. На эту тему уже написано достаточно публикаций. Вместо давайте посмотрим, как на практике можно работать с процессами. В качестве тестовой ОС как обычно выступает ОС Linux Ubuntu 22.04.

Получаем список процессов

Каждый процесс имеет свои атрибуты. Это прежде всего идентификатор процесса (PID), также это образ, исполняемый файл, статус выполнения, атрибуты безопасности и т.д.

Получить список процессов с основными атрибутами можно с помощью команды:

Если необходимо получить информацию по конкретному процессу, то можно воспользоваться командой:

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

В результате мы получаем дерево процессов, в котором видно какой процесс является родительским для других процессов. Конечно, такую зависимость можно построить и на основании вывода ps сопоставив значение поля PPID (родительский процесс) интересующего процесса с PID соответствующего процесса. Но в виде дерева все выглядит гораздо нагляднее.

Приоритетные и фоновые процессы

Процессы могут быть приоритетными и фоновыми. Приоритетный процесс у нас по сути «прикреплен» к текущему терминалу. То есть он может считывать и передавать данные на стандартные устройства ввода/вывода. Но при этом, наш рабочий терминал будет заблокирован до тех пор, пока запущенный процесс не выполнится. По умолчанию, когда пользователь вводит команду на терминале, создается приоритетный процесс. Это удобно при работе с консольными командами, не требующими значительного времени на выполнение. Но это очень неудобно при использовании различных скриптов, работа которых занимает значительный период времени.

Для таких случаев лучше использовать фоновые процессы. Такие процессы не занимают текущий терминал, то есть мы можем одновременно с выполнением фонового процесса работать с другими командами, запускать процессы и т.д. Фоновый процесс также называется Заданием (Job).

Запустить процесс в фоновом режиме очень просто, достаточно добавить знак & после команды:

После запуска выведется строка с номером задания (в скобках) и PID, появится приглашение на ввод команды в текущем терминале. При этом, номера заданий относятся только к текущему терминалу.

Однако, выполнение этой команды завершится слишком быстро, поэтому для дальнейших примеров я использую скрипт, использующий бесконечный цикл с условием while true…

После запуска в фоновом режиме посмотреть выполнение задание можно с помощью команды jobs:

Приоритетные задачи можно также превращать в фоновые и возвращать обратно в приоритетные.

Читайте также:  Linux script service running

В качестве примера я снова запущу свой скрипт. Нажатие Ctrl-Z приведет к остановке данного процесса. На рисунке ниже это вывод первой команды jobs. Далее остановленный процесс можно снова запустить в фоновом режиме с помощью команды bg (background). Во втором выводе jobs скрипт запущен со знаком &. И для того, чтобы вернуть процесс в фоновый режим воспользуемся командой fg (foreground).

Вообще, команды fg и bg переводят из/в фоновый режим задание с указанным номером. Но, если номер не указан, действие применяется к последнему созданному заданию, как в нашем случае.

В случае, если нам необходимо завершить процесс, проще всего воспользоваться командой

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

В таком случае передается более мощный сигнал SIGKILL, который нельзя проигнорировать или заблокировать. Как жаль, что такой команды нет в Windows.

Виртуальная файловая система procfs

Виртуальная файловая система procfs, как можно понять из названия расположена только в памяти и не хранится на жестком диске постоянно. Доступ к ней можно получить, обратившись к каталогу /proc.

Как можно увидеть, в этом каталоге содержатся подкаталоги, соответствующие PID процессов. У каждого процесса есть своя запись в /proc с идентификатором в названии. В каждом из этих подкаталогов можно найти ряд файлов, связанных с данным процессом.

Вот основные файлы, которые есть в каждом каталоге процесса:

cmdline — полная командная строка процесса.

В примере для демона SSH видим следующее:

cwd — символьная ссылка на текущий каталог процесса.

exe — символьная ссылка на файл, который должен выполняться.

environ — переменные среды процесса.

fd — содержит ссылку на дескрипторы каждого открытого файла.

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

Заключение

В этой статье были рассмотрены практические аспекты работы с процессами в ОС Linux. За рамками этой статьи осталась работа с приоритетами и сигналами и многое другое, что будет рассмотрено в следующей статье.

А на бесплатном уроке специализации Linux мои коллеги из OTUS расскажут про базовые команды в Linux. Зарегистрироваться на вебинар можно по этой ссылке.

Источник

How to get process ID of background process?

I start a background process from my shell script, and I would like to kill this process when my script finishes. How to get the PID of this process from my shell script? As far as I can see variable $! contains the PID of the current script, not the background process.

9 Answers 9

You need to save the PID of the background process at the time you start it:

foo & FOO_PID=$! # do other stuff kill $FOO_PID 

You cannot use job control, since that is an interactive feature and tied to a controlling terminal. A script will not necessarily have a terminal attached at all so job control will not necessarily be available.

Читайте также:  Линукс минт как переключить язык

Since $! returns the last background process’s pid. Is it possible that something starts between foo and $! , and we get that something’s pid instead of foo ‘s?

@WiSaGaN: No. There is nothing between those lines. Any other activity on the system will not affect this. $! will expand to the PID of the last background process in that shell.

. which hoses you if foo happens to be multiple piped commands (eg. tail -f somefile.txt | grep sometext ). In such cases, you will get the PID of the grep command from $! rather than the tail command if that’s what you were looking for. You will need to use jobs or ps or the likes in this instance.

@JohnRix: Not necessarily. You will get the pid of grep , but if you kill that, tail will get a SIGPIPE when it tries to write to the pipe. But as soon as you try to get into any tricky process management/control, bash/shell becomes quite painful.

Another worthy solution is suggested in (a comment to an answer to) How to get pid of just started process: oh, and the «oneliner»: /bin/sh -c ‘echo $$>/tmp/my.pid && exec program args’ & – sysfault Nov 24 ’10 at 14:28

You can use the jobs -l command to get to a particular jobL

^Z [1]+ Stopped guard my_mac:workspace r$ jobs -l [1]+ 46841 Suspended: 18 guard 

In this case, 46841 is the PID.

-l Report the process group ID and working directory of the jobs.

jobs -p is another option which shows just the PIDs.

@Phil To list pids only : jobs -p. To list pid of a certain job: jobs -p %3. No need to process output.

@Erik with different commands / arguments you change the context of my comment. Without the additional argument suggested the output requires processing. Suggest an improvement to the answer!

Saving the PID from $! just after you started it is more portable and more straightforward in most situations. That’s what the currently accepted answer does.

@Calimo I agree that jobs is the way to go in an interactive session, but this is posted as an answer to a question specifically about how to do this programmatically from a script.

Here’s a sample transcript from a bash session ( %1 refers to the ordinal number of background process as seen from jobs ):

$ echo $$ 3748 $ sleep 100 & [1] 192 $ echo $! 192 $ kill %1 [1]+ Terminated sleep 100 

Note that $$ is not always the current PID. For example, if you define a new function in bash and run the function in the background, the $$ within that function contains the PID of the process that started the function in the background. If you need PID of the actual process running any given code, you have to use $BASHPID , instead.

Читайте также:  Linux and other operating system

An even simpler way to kill all child process of a bash script:

The -P flag works the same way with pkill and pgrep — it gets child processes, only with pkill the child processes get killed and with pgrep child PIDs are printed to stdout.

@lepe: Not quite. If you are a grandparent, this won’t work: after bash -c ‘bash -c «sleep 300 &»‘ & running pgrep -P $$ shows nothing, because the sleep will not be a direct child of your shell.

@AlexeyPolonsky: it should be: kill all child procs of a shell, not a script. Because $$ refers to the current shell.

performing bash -c ‘bash -c «sleep 300 &»‘ & ; pgrep -P $$ , I get on stdout [1] . So at least it shows something, but this is probably not the output of pgrep`

Even processes can deattach them from parent process. Simple trick is to call fork (create a grandchild) and then just let the child process exit while grandchild continues doing the work. (daemonization is the keyword) But even if child keeps running too pkill -P isn’t enough to propagate signal to grandchilds. Tool like pstree is required to follow whole dependant process tree. But this won’t catch daemons started from the process as their parent is process 1. eg: bash -c ‘bash -c «sleep 10 & wait $!»‘ & sleep 0.1; pstree -p $$

this is what I have done. Check it out, hope it can help.

#!/bin/bash # # So something to show. echo "UNO" > UNO.txt echo "DOS" > DOS.txt # # Initialize Pid List dPidLst="" # # Generate background processes tail -f UNO.txt& dPidLst="$dPidLst $!" tail -f DOS.txt& dPidLst="$dPidLst $!" # # Report process IDs echo PID=$$ echo dPidLst=$dPidLst # # Show process on current shell ps -f # # Start killing background processes from list for dPid in $dPidLst do echo killing $dPid. Process is still there. ps | grep $dPid kill $dPid ps | grep $dPid echo Just ran "'"ps"'" command, $dPid must not show again. done 

Then just run it as: ./bgkill.sh with proper permissions of course

root@umsstd22 [P]:~# ./bgkill.sh PID=23757 dPidLst= 23758 23759 UNO DOS UID PID PPID C STIME TTY TIME CMD root 3937 3935 0 11:07 pts/5 00:00:00 -bash root 23757 3937 0 11:55 pts/5 00:00:00 /bin/bash ./bgkill.sh root 23758 23757 0 11:55 pts/5 00:00:00 tail -f UNO.txt root 23759 23757 0 11:55 pts/5 00:00:00 tail -f DOS.txt root 23760 23757 0 11:55 pts/5 00:00:00 ps -f killing 23758. Process is still there. 23758 pts/5 00:00:00 tail ./bgkill.sh: line 24: 23758 Terminated tail -f UNO.txt Just ran 'ps' command, 23758 must not show again. killing 23759. Process is still there. 23759 pts/5 00:00:00 tail ./bgkill.sh: line 24: 23759 Terminated tail -f DOS.txt Just ran 'ps' command, 23759 must not show again. root@umsstd22 [P]:~# ps -f UID PID PPID C STIME TTY TIME CMD root 3937 3935 0 11:07 pts/5 00:00:00 -bash root 24200 3937 0 11:56 pts/5 00:00:00 ps -f 

Источник

Оцените статью
Adblock
detector