قالب وردپرس درنا توس
Home / Tips and Tricks / Bash process termination hacks – CloudSavvy IT

Bash process termination hacks – CloudSavvy IT



Bash Shell

When developing multi-threaded Bash code, managing server processes, or creating process watchdogs, one of the biggest challenges is usually properly, efficiently, and accurately terminating existing Bash processes. This article shows you how.

What is a Bash process?

A Bash process is simply an executable file that is executed. For example, starting the calculator in your desktop environment creates a bash process. Such a bash has two main process IDs, namely the PID and the PPID, the Process ID, and the Identification of the parent process.

In summary, the PID contains a number-based unique ID for a given running application (ie process), while the PPID for a given running application (i.e. process) it saves Parent PID of the process that started this new application, hence the term ̵

6;Parent’.

You can also immediately see how this forms a tree-like structure, linking all processes together down to the root / first process that a PPID from 0.

Root processes on Linux

For a related article that provides additional insights and a practical example of PID and PPID, you can read our Export Variables in Bash: Read the Why and How article.

Bash process management seems simple at first glance (just run ps -ef on your terminal’s command line to see all processes on your system preceded by their PID and PPID IDs.

Even terminating a process may seem easy, but caveats and pitfalls quickly arise when dealing with more complex process management systems.

End a bash process

Let’s start simply by it gnome-calculator at the command line and then end the process.

gnome calculator & ps -ef |  grep gnome-calculator kill -9 $ RELEVANT_PID

A simple process kill in Linux

We started gnome-calculator in background mode (by & at the end of the command) so that we can immediately get our terminal prompt back without having to start a new terminal session.

Then we used ps -ef in combination with a pipe (|) and the grep command to get the process ID (PID) of our calculator. We then ended it with a signal 9 kill order. To replace $RELEVANT_PID in the code with the PID reported by ps if you try this code.

Note that the background process is immediately terminated by the kill -9 instruction. However, the Bash command prompt returns so quickly that it is back even before the process scheduler can report that the background process has ended.

And it will only do this if that notification is in line with existing work i.e. it is more pull based than push based. When we press enter, the system checks and informs us that the first background process has now ended, or rather ended / ended; [1]+ Killed gnome-calculator.

Returning to our kill command, a signal 9 kill is one of the most destructive murders there is. It basically ends the program on the spot without being nice about it. You can view the ‘Signal Numbering for Standard Signals’ section, accessible from the man signal.7 command executed at your terminal command prompt for a list of all available signals and their corresponding numbers.

For the purposes of this article, we use signal 9 to always end a process immediately and effectively. But even if you have a signal 9 kill / process termination, sometimes a process can hang in a defunct state.

It doesn’t happen often in general DevOps work, and when it does, it usually means that there were some serious issues with the program’s code (the process that is running) or with the system hardware or operating system in the beginning .

Avoid errors and only select own processes

If you start over with the above process, there is a way to fix the PID selection so we don’t have to type in manually, and so we can use it from a script? There is certainly;

gnome-calculator &
ps -ef | grep 'gnome-calculator' | grep -v 'grep' | awk '{print $2}'
ps -ef | grep 'gnome-calculator' | grep -v 'grep' | awk '{print $2}' | xargs kill -9

Better defined process termination in Linux

Here we started our again gnome-calculator in background mode, and used again ps and grep to find our process. That’s where the similarity ends. In the following instruction within the Bash set pipes (passing information from the previous command to the next using a pipe symbol: |) we close the grep process itself (also listed as part of the ps output as it is executed during our command string and thus itself picked up by the grep), with help from -v option to grep and exclude the word 'grep'.

Finally, we print it PID (process ID) of all discovered processes using awk and printing the second ($2) column of output only. We only see that a few PID is returned, which corresponds to the fact that we only have one gnome-calculator started.

Our last command adds a xargs command with a kill -9 instruction to end our process (es). xargs works as a pipe on its own, but it is better able to handle and correctly pass various input information, thus allowing certain programs such as kill (which by nature cannot understand if they are clear PIDare sent there) to accept direct entry, or rather options – such as the process ID sent here. Note that xargs is preceded by a pipe itself.

Our inclusion of one grep -v 'grep' not only avoids the mistake of the ultimate kill command can do it PID associated with the original grep command (since it has since been terminated, having fulfilled its duty of grepping for the 'gnome-calculator' text), second, it also avoids the risk of terminating another, newer command / process that may have been started since the original grep terminated, with the same process ID! While the chances of this happening are slim, it is possible.

Processing these things in our assignment looks better, but it’s not perfect yet. What is this a server with 10 users and all 10 started with a calculator? Assuming we have sudo-like permissions, do we really want to end the other users’ computing processes? Probably not. So we can go one step further and define our mission as follows:

gnome calculator & ps -ef |  grep 'gnome calculator' |  grep -v 'grep' |  grep "$ (whoami)" |  awk '{print $ 2}' ps -ef |  grep 'gnome calculator' |  grep -v 'grep' |  grep "$ (whoami)" |  awk '{print $ 2}' |  xargs kill -9

Exclude owned processes from a process termination order

In this example we have inserted a small extra command, namely grep "$(whoami)", which ran a subshell ($(...)) and then executes whoami within that subshell. The whoami command will return to the terminal of the currently logged in users. Bingo! We now only end our own processes.

Perfect? No, unfortunately errors are still possible, even with such a fine-tuned command line. For example, if the process list contains local or odd characters, our grep may still fail. Perhaps the most secure version is something similar to:

gnome-calculator &
ps -ef | grep -Ei --binary-files=text "^$(whoami) [0-9 ]+:.*gnome-calculator$" | grep --binary-files=text -v 'grep' | awk '{print $2}' | grep --binary-files=text  -o '[0-9]+' | xargs -I{} kill -9 "{}"

A more secure version or a termination command for multiple processes

In this example, we have our grep command much more limited with a regular expression: start (denoted by ^) with the username (with whoami in a subshell), followed by a mandatory space, followed by characters only 0-9 and space, at least one or more (as indicated by +), followed by a mandatory colon (part of the time), followed by any character up to our program name, which must be filled to the end of the line (as indicated by $). The grep uses extended regular expressions (-E), and is not case sensitive (-i option, or plain i when added to the existing one -E option)

We’ve also protected our grep from the strange possibility of locale or strange characters by --binary-files=text, and we’ve written our xargs in a safer way by specifying a replacement string and quoting the replacement string.

Finally, we have an extra grep -o with a regular expression that searches for the numbers 0-9 nothing but. So even if a program tried to trick this command line killing this process, it would be harder to do that.

As an interesting alternative to defining a parse command line, you may also want to take a look at it killall order:

gnome-calculator &
killall 'gnome-calculator'

Example of a killall command excution

For more information about this command, you can open the manual with man killall. The killall command also allows you to set options such as --user to kill only processes that the specified user owns etc.

Shut down

By handling processes in different ways, we can write process watchdog scripts, automate process handling, develop multi-threaded bash code better, manage processes better, and more. Enjoy your new found Bash skills!


Source link