Tuesday 29 November 2016

Making sure running commands keep running


The title of the article may seem a bit misleading but this is actually about job control & how we can make sure that long running commands don't die out once we close our terminal windows.

So let's start with job control first. In linux if we want to run a command in the background we place a & symbol after it. For example

[root@centops ~]# sleep 5000 &
[1] 18250
[root@centops ~]#

As soon as we press enter we are returned to the prompt & the system gives us a job number (in this case 1) & a PID 18250.

[root@centops ~]# pgrep -fl sleep
18250 sleep 5000
[root@centops ~]#

So, what if we want to place a running job in the background in case we forgot to mention & when we executed the command. Well, that's easy. We just need to press ctrl+z to suspend the job & then use bg to start the job in background.

[root@centops ~]# sleep 7000
^Z
[3]+  Stopped                 sleep 7000
[root@centops ~]# bg %3
[3]+ sleep 7000 &
[root@centops ~]#

To view currently running/stopped jobs along with their PID, type jobs -l.

[root@centops ~]# jobs -l
[1]  18250 Running                 sleep 5000 &
[2]- 18297 Running                 sleep 6000 &
[3]+ 18300 Running                 sleep 7000 &
[root@centops ~]#

to bring a job to the foreground, type fg followed by % and then the job number. For example.

[root@centops ~]# fg %2
sleep 6000
^Z
[2]+  Stopped                 sleep 6000
[root@centops ~]# bg %2
[2]+ sleep 6000 &
[root@centops ~]#
[root@centops ~]# jobs -l
[1]  18250 Running                 sleep 5000 &
[2]- 18297 Running                 sleep 6000 &
[3]+ 18300 Running                 sleep 7000 &
[root@centops ~]#


In the above jobs -l output, the + symbol indicates the job that was sent to the background most recently. To terminate a job, bring the job to the foreground & press ctrl+c.

All the jobs that we have running here will be sent a hang up signal once we close the terminal & will be gone. The hang up signal tells the running jobs that their controlling terminal window has been terminated so the jobs should terminate themselves. 
Now let's look at preserving our jobs after closure of the terminal window. 

Use nohup:
nohup is a common way of preventing jobs from terminating once we close the terminal window. The syntax for starting a job using nohup in background is nohup <command> &.
For example,

[root@centops ~]# nohup sleep 600 &
[1] 18486
[root@centops ~]# nohup: ignoring input and appending output to `nohup.out'
[root@centops ~]#

The nohup command will send all it's output to a file named nohup.out. If the command is generating a lot of output then the size of the nohup.out file might be something to lookout for.


Use disown:
nohup is great as long as you remember to to type it before typing the command since nohup needs to proceed the command. What if we forgot to do that & still want to prevent our job from being killed off when we close the terminal. In that case we can use disown. disown works in a fashion similar to that of bg & fg in the sense that it accepts a % followed by a job number as it's input but it's functionality is totally different.
Disown removes a process from the shell's control. So if we disown the job, it'll keep running in the background but we would have foresighted control of it i.e. the job will no longer be visible in the jobs -l output & we won't be able to bring it back to the background if we need to. here's a demo.

[root@centops ~]#  sleep 600 &
[1] 18507
[root@centops ~]# jobs -l
[1]+ 18507 Running                 sleep 600 &
[root@centops ~]#
[root@centops ~]# disown %1
[root@centops ~]#
[root@centops ~]# jobs -l
[root@centops ~]#
[root@centops ~]# pgrep -fl sleep
18507 sleep 600
[root@centops ~]#

In the above example I started a sleep command in the background. I then disowned the job after which it was no longer visible in jobs -l output but when I checked the PID, I was able to find the command still running. Now if I closed my terminal window, the disowned job will continue to run in the background until it completes.


Use screen:
Disown is nice but the problem is that we can't foreground a disowned job in future in another terminal. Screen is an extremely versatile tool & what I'm illustrating here is a small part of the complete tool set that screen provides. So here's how we do it.
Type the screen command to start a screen session. Type the command you need to execute & press & to put it in the background for execution. Now we'll detach the screen. To do this, press ctrl+a followed by d.
Now open another terminal session & type screen -dr. This will re-attach the most recently detached screen i.e. the one we were working on before. To terminate a screen session, just press exit.

No comments:

Post a Comment

Using capture groups in grep in Linux

Introduction Let me start by saying that this article isn't about capture groups in grep per se. What we are going to do here with gr...