Linux processes run reliably in the background

Posted by z1haze on Sun, 16 Jan 2022 07:41:43 +0100

1. Scenario requirements

Scenario: if there is only a temporary command that needs to run for a long time, what is the easiest way to ensure its stable operation in the background?

The origin of hangup name in the early versions of Unix, each terminal would communicate with the system through modem. When the user logs out, the modem will hang up. Similarly, when the modem is disconnected, it will send a hangup signal to the terminal to notify it to close all sub processes.

resolvent:

We know that when the user logs out or the network is disconnected, the terminal will receive a HUP (hangup) signal to close all its sub processes. Therefore, our solution has two ways: either let the process ignore the HUP signal, or let the process run in a new session and become a child process that does not belong to this terminal.

2. nohup command

Nohup is undoubtedly our first idea. As the name suggests, the purpose of nohup is to make the submitted command ignore the hangup signal. Let's take a look at the help information of nohup:

NOHUP(1)                        User Commands                        NOHUP(1)
 
NAME
       nohup - run a command immune to hangups, with output to a non-tty
 
SYNOPSIS
       nohup COMMAND [ARG]...
       nohup OPTION
 
DESCRIPTION
       Run COMMAND, ignoring hangup signals.
 
       --help display this help and exit
 
       --version
              output version information and exit

It can be seen that the use of nohup is very convenient. Just add nohup before the command to be processed. The standard output and standard error will be redirected to nohup by default Out file. Generally, we can add "&" at the end to run the command in the background at the same time, or use "> filename 2 > & 1" to change the default redirect file name.
nohup example

~]# nohup ping www.ibm.com &
[1] 3059nohup: appending output to `nohup.out'
~]# ps -ef |grep 3059
root      3059   984  0 21:06 pts/3    00:00:00 ping www.ibm.comroot      3067   984  0 21:06 pts/3    00:00:00 grep 3059

3. setsid command

nohup can undoubtedly prevent our process from being interrupted by ignoring the HUP signal, but if we think from another angle, if our process does not belong to the sub process of the terminal receiving the HUP signal, it will not be affected by the HUP signal. Setsid can help us do this. Let's take a look at the help information of setsid:

SETSID(8)                 Linux Programmer's Manual                 SETSID(8)
 
NAME
       setsid - run a program in a new session
 
SYNOPSIS
       setsid program [ arg ... ]
 
DESCRIPTION
       setsid runs a program in a new session.

It can be seen that the use of setsid is also very convenient. You only need to add setsid before the command to be processed.
setsid example

~]# setsid ping www.ibm.com
~]# ps -ef |grep www.ibm.com
root     31094     1  0 07:28 ?        00:00:00 ping www.ibm.comroot     31102 29217  0 07:29 pts/4    00:00:00 grep www.ibm.com

It should be noted that in the above example, our process ID(PID) is 31094, and its parent ID (PPID) is 1 (i.e. init process ID), which is not the process ID of the current terminal. Please compare this example with the parent ID in the nohup example.

4. &

Here's another tip about subshell. We know that including one or more names in "()" can make these commands run in the sub shell, so as to expand many interesting functions. We are going to discuss one of them now.
When we put "&" into "()", we will find that the submitted job is not in the job list, that is, it cannot be viewed through jobs. Let's see why we can avoid the influence of HUP signal.
subshell example

~]# (ping www.ibm.com &)
~]# ps -ef |grep www.ibm.com
root     16270     1  0 14:13 pts/4    00:00:00 ping www.ibm.comroot     16278 15362  0 14:13 pts/4    00:00:00 grep www.ibm.com

As can be seen from the above example, the parent ID (PPID) of the newly submitted process is 1 (PID of init process), which is not the process ID of the current terminal. Therefore, it does not belong to the sub process of the current terminal, so it will not be affected by the HUP signal of the current terminal.

5. disown

Scenario: we already know that if nohup or setsid is added before the command in advance, the influence of HUP signal can be avoided. However, if we have submitted the command without any processing, how can we remedy it to avoid the influence of HUP signal?
Solution: it's too late to add nohup or setsid. You can only solve this problem through job scheduling and disown. Let's take a look at the help information of disown:

disown [-ar] [-h] [jobspec ...]
    Without options, each jobspec is  removed  from  the  table  of
    active  jobs.   If  the -h option is given, each jobspec is not
    removed from the table, but is marked so  that  SIGHUP  is  not
    sent  to the job if the shell receives a SIGHUP.  If no jobspec
    is present, and neither the -a nor the -r option  is  supplied,
    the  current  job  is  used.  If no jobspec is supplied, the -a
    option means to remove or mark all jobs; the -r option  without
    a  jobspec  argument  restricts operation to running jobs.  The
    return value is 0 unless a jobspec does  not  specify  a  valid
    job.

It can be seen that we can achieve our goal in the following ways.
Flexible use of CTRL-z

In our daily work, we can use CTRL-z to suspend the current process to the background, pause, perform some other operations, and then use fg to put the suspended process back to the foreground (or bg to put the suspended process in the background) to continue running. In this way, we can flexibly switch and run multiple tasks in one terminal, which is particularly useful when debugging code. Because when the code editor is suspended to the background and then placed back, the cursor positioning still stays at the position of the last suspension, avoiding the trouble of relocation.

Use disown -h jobspec to make a job ignore the HUP signal.
Use disown -ah to make all jobs ignore the HUP signal.
Use disown -rh to make running jobs ignore HUP signals.

It should be noted that after using disown, the target job will be removed from the job list. We can no longer use jobs to view it, but we can still find it with ps -ef.

But there is another problem. The operation object of this method is a job. If we add "&" at the end of the command to make it a job and run in the background, then everything will be fine. We can get the list of all jobs through the jobs command. But if you don't run the current command as a job, how can you get its job number? The answer is to use CTRL-z (hold down the CTRL key while holding down the z key)!
The purpose of CTRL-z is to Suspend the current process, and then we can use the jobs command to query its job number, and then bg jobspec to put it in the background and continue running. It should be noted that if suspending will affect the running results of the current process, please use this method with caution.

Disown ex amp le 1 (if the command has been put into the background with "&" when submitting the command, you can directly use "disown")

build]# cp -r testLargeFile largeFile &[1] 4825
build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile &
build]# disown -h %1
build]# ps -ef |grep largeFile
root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFileroot      4853   968  0 09:46 pts/4    00:00:00 grep largeFile

Logotdisown ex amp le 2 (if "&" is not used to put the command into the background when submitting the command, you can use CTRL-z and "bg" to put it into the background, and then use "disown")

build]# cp -r testLargeFile largeFile2
[1]+  Stopped                 cp -i -r testLargeFile largeFile2
build]# bg %1
[1]+ cp -i -r testLargeFile largeFile2 &
build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile2 &
build]# disown -h %1
build]# ps -ef |grep largeFile2
root      5790  5577  1 10:04 pts/3    00:00:00 cp -i -r testLargeFile largeFile2root      5824  5577  0 10:05 pts/3    00:00:00 grep largeFile2

6. screen

Scenario: we already know how to protect the process from HUP signals, but if a large number of such commands need to be run in a stable background, how to avoid doing this for each command?

resolvent:

At this time, the most convenient method is screen. In short, screen provides ANSI/VT100 terminal simulator, which enables it to run multiple full screen pseudo terminals under a real terminal. Screen has many parameters and powerful functions. Here we only introduce its common functions and briefly analyze why using screen can avoid the influence of HUP signal. Let's first look at the help information of screen:

SCREEN(1)                                                           SCREEN(1)
 
NAME
       screen - screen manager with VT100/ANSI terminal emulation
 
SYNOPSIS
       screen [ -options ] [ cmd [ args ] ]
       screen -r [[pid.]tty[.host]]
       screen -r sessionowner/[[pid.]tty[.host]]
 
DESCRIPTION
       Screen  is  a  full-screen  window manager that multiplexes a physical
       terminal between several  processes  (typically  interactive  shells).
       Each  virtual  terminal provides the functions of a DEC VT100 terminal
       and, in addition, several control functions from the  ISO  6429  (ECMA
       48,  ANSI  X3.64)  and ISO 2022 standards (e.g. insert/delete line and
       support for multiple character sets).  There is a  scrollback  history
       buffer  for  each virtual terminal and a copy-and-paste mechanism that
       allows moving text regions between windows.

screen is very convenient to use. There are several common options:
Use screen -dmS session name to establish a session in disconnected mode (and specify its session name).
Use screen -list to list all sessions.
Use screen -r session name to reconnect to the specified session.
Use the shortcut key CTRL-a d to temporarily disconnect the current session.
screen example

~]# screen -dmS Urumchi
~]# screen -list
There is a screen on:
        12842.Urumchi   (Detached)
1 Socket in /tmp/screens/S-root.
 
~]# screen -r Urumchi

When we connect to the screen session with "- r", we can do whatever we want in this pseudo terminal. We don't have to worry about the impact of HUP signal on our process, and we don't have to add "nohup" or "setsid" before each command. Why? Let me look at the following two examples.

  1. The process tree of the new process when screen is not used
~]# ping www.google.com &
[1] 9499
~]# pstree -H 9499
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─2*[sendmail] 
     ├─sshd─┬─sshd───bash───pstree
     │       └─sshd───bash───ping

We can see that when screen is not used, the bash we are in is a child process of sshd. When ssh is disconnected, the HUP signal will naturally affect all the child processes below it (including our newly established ping process).

  1. The process tree of the new process after screen is used
~]# screen -r Urumchi
~]# ping www.ibm.com &
[1] 9488
[root@pvcent107 ~]# pstree -H 9488
init─┬─Xvnc
     ├─acpid
     ├─atd
     ├─screen───bash───ping
     ├─2*[sendmail]

It is different when screen is used. bash is the child process of screen, and screen is the child process of init (PID 1). Then, when ssh is disconnected, the HUP signal will not affect the child processes under screen.

7. Summary

Now that several methods have been introduced, we can choose different schemes according to different scenarios. nohup/setsid is undoubtedly the most convenient method when it is needed temporarily. disown can help us remedy the currently running jobs after coming, and screen is the best choice for mass operation.

Topics: Linux Operation & Maintenance server