It is common to log in to a remote Linux server using Telnet/SSH and run some time-consuming tasks, only to fail in the middle of the task due to network instability. How can commands be submitted without the interference of locally closing terminal Windows/network disconnection? Here are some examples of how you can approach this problem in different ways for different scenarios.

nohup/setsid/&

Scene:

If there is only a temporary command that needs to be run for a long time, what is the easiest way to ensure that it runs stably in the background?

The origin of hangup’s name

In earlier versions of Unix, each terminal communicated with the system through a modem. When the user logout, the modem will hang up the call. Similarly, when the modem disconnects, it sends a hangup signal to the terminal to tell it to shut down all child processes.

Solutions:

As we know, when a user logout or network disconnection occurs, an endpoint receives an HUP signal and shuts down all of its child processes. Therefore, we have two solutions: 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.

1. nohup

Nohup was definitely the first thing we thought of. As the name suggests, the purpose of nohup is to make submitted commands ignore the hangup signal. Let’s start with Nohup’s help message:

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 exitCopy the code

As you can see, nohup is very convenient to use. Just add nohup before the command to be processed, and the standard output and standard error are redirected to the nohup.out file. You can also use “>filename 2>&1” to change the default redirection filename.

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

2. setsid

Nohup can no doubt avoid interruption by ignoring THE HUP signal, but if we think about it differently, if our process is not a child of the terminal receiving the HUP signal, then it will not be affected by the HUP signal. Setsid can help us do just that. Let’s take a look at setsid’s help first:

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.Copy the code

Setsid is also very convenient to use, and it is only necessary to add setSID before the command to be processed.

Setsid sample
[root@pvcent107 ~]# setsid ping www.ibm.com
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     31094     10 07:28? 00:00:00 ping www.ibm.com root 31102 29217 0 07:29 pts/4 00:00:00 grep www.ibm.com [root@pvcent107 ~]#Copy the code

Note that 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. Compare this example to the parent ID in the nohup example.

3. &

Here’s another tip for subshells. We know that including one or more names in “()” allows these commands to run in a subshell, extending a number of interesting features, one of which we’ll discuss now.

When we put the “&” inside the “()”, we see that the submitted job is not in the job list, that is, it cannot be viewed by Jobs. Let’s take a look at why you can avoid the HUP signal.

The subshell is sample
[root@pvcent107 ~]# (ping www.ibm.com &)
[root@pvcent107 ~]# ps -ef |grep www.ibm.com
root     16270     1  0 14:13 pts/4    00:00:00 ping www.ibm.com
root     16278 15362  0 14:13 pts/4    00:00:00 grep www.ibm.com
[root@pvcent107 ~]#Copy the code

As shown in 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 child process of the current terminal and therefore is not affected by the HUP signal of the current terminal.


disown

Scene:

We already know that the HUP signal can be avoided if the command is preceded by nohUP or setSID. But if we submit the command without any processing, how can we remedy it to avoid the HUP signal?

Solutions:

It is too late to add nohup or setSID, and the only solution is job scheduling and disown. Let’s take a look at disown’s help information:

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.Copy the code

As can be seen, we can achieve our goal in the following ways.

Be flexible with CtrL-Z

In our daily work, we can use Ctrl-Z to suspend the current process in the background, do something else, and then use FG to put the pending process back in the foreground (or bg to put the pending process in the background) to continue running. This gives us the flexibility to switch between running multiple tasks within a terminal, which is especially useful when debugging code. Because when you suspend the code editor in the background and then put it back in, the cursor position remains exactly where it was when it was last suspended, you avoid repositioning.

  • withdisown -h jobspecTo make theA jobIgnore the HUP signal.
  • withdisown -ah To make theAll the homeworkHUP signals are ignored.
  • withdisown -rh To make theRunning jobsIgnore the HUP signal.

Note that when disown is used, the target job is removed from the job list, and we can no longer view it using Jobs, but we can still find it using ps-ef.

If we run the command with an ampersand at the end to make it a job and run it in the background, we’ll be all right. We can use the Jobs command to get a list of all the jobs. But if the current command is not running as a job, how do you get its job number? The answer is ctrl-Z (CTRL + Z)!

Ctrl-z is used to Suspend the current process, and we can use the jobs command to query its job number, then use bg JobSpec to put it in the background and continue running. Caution Use this method with caution if the suspension will affect the running results of the current process.

Disown Example 1 (If you have already put the command into the background with &, you can use “disown” directly)
[root@pvcent107 build]# cp -r testLargeFile largeFile &
[1] 4825
[root@pvcent107 build]# jobs
[1]+  Running                 cp -i -r testLargeFile largeFile &
[root@pvcent107 build]# disown -h %1
[root@pvcent107 build]# ps -ef |grep largeFile
root      4825   968  1 09:46 pts/4    00:00:00 cp -i -r testLargeFile largeFile
root      4853   968  0 09:46 pts/4    00:00:00 grep largeFile
[root@pvcent107 build]# logoutCopy the code

Disown Example 2 (If the command is not put in the background with &, use Ctrl-Z and bg to put it in the background, and then use Disown)
[root@pvcent107 build]# cp -r testLargeFile largeFile2 [1]+ Stopped cp -i -r testLargeFile largeFile2 [root@pvcent107 build]# bg %1 [1]+ cp -i -r testLargeFile largeFile2 & [root@pvcent107 build]# jobs [1]+ Running cp -i -r testLargeFile largeFile2 & [root@pvcent107 build]# disown -h %1 [root@pvcent107 build]# ps -ef |grep largeFile2 root 5790 5577 1 10:04  pts/3 00:00:00 cp -i -r testLargeFile largeFile2 root 5824 5577 0 10:05 pts/3 00:00:00 grep largeFile2 [root@pvcent107 build]#Copy the code


screen

Scene:

We already know how to insulate processes from HUP signals, but if there are a large number of these commands that need to be run in a stable background, how do we avoid doing this for every one of them?

Solutions:

The most convenient method in this case is Screen. Simply put, Screen provides an ANSI/VT100 terminal emulator that enables it to run multiple full-screen pseudo-terminals on a real terminal. Screen has many parameters and has very powerful functions. Here we only introduce its common functions and briefly analyze why screen can avoid the influence of HUP signal. Let’s take a look at screen’s help:

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, ISO 2022 standards (e.g. insert/delete line and support for multiple character sets) scrollback history buffer for each virtual terminal and a copy-and-paste mechanism that allows moving text regions between windows.Copy the code

Screen is easy to use with the following common options:

  • withscreen -dmS session nameTo establish a session in disconnect mode (and specify its session name).
  • withscreen -list To list all sessions.
  • withscreen -r session nameTo reconnect the specified session.
  • Use shortcutsCTRL-a d To temporarily disconnect the current session.
Screen sample
[root@pvcent107 ~]# screen -dmS Urumchi
[root@pvcent107 ~]# screen -list
There is a screen on:
        12842.Urumchi   (Detached)
1 Socket in /tmp/screens/S-root.

[root@pvcent107 ~]# screen -r UrumchiCopy the code

When we connect to the Screen session with “-r”, we can do whatever we want in the pseudo terminal without worrying about the HUP signal affecting our process or adding “nohup” or “setsid” to every command. Why is that? Let me look at the following two examples.

1. Process tree of the new process without Screen
[root@pvcent107 ~]# ping www.google.com & [1] 9499 [root@pvcent107 ~]# pstREE -h 9499 init─┬─Xvnc ├─ ACPID ├─ ATD ├ ─ 2 * [sendmail]├ ─ SSHD ─ ┬─ SSHD ─ ─ ─ bash ─ ─ ─ pstree │└ ─ SSHD ─ ─ ─ bash ─ ─ ─ pingCopy the code

We can see that the bash we were in before screen was a child of SSHD, and when SSH was disconnected, the HUP signal naturally affected all of its children (including our newly created ping process).

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

This is different with Screen, where bash is a child of Screen, and screen is a child of init (PID 1). So when SSH disconnects, the HUP signal does not affect the child processes under Screen.


conclusion

Now that several methods have been introduced, we can choose different solutions according to different scenarios. Nohup/setSID is definitely the most convenient method for temporary needs, disown can help us to recover jobs that are already running after the fact, and Screen is the best choice for bulk operations.