Linux Bash Scripting Part5 – Signals and Jobs
In the previous post, we talked about input, output, and redirection in bash scripts. Today we will learn how to run and control them on a Linux system. Till now, we can run scripts only from the command-line interface, but this isn’t the only way to run Linux bash scripts.
This post describes the different ways to control your Linux bash scripts.
- 1 Linux signals
- 2 Stop a process
- 3 Pause a process
- 4 Trap Signals
- 5 Trapping the script exit
- 6 Modifying or removing a trap
- 7 Running Linux Bash scripts in background mode
- 8 Running scripts without a hang-up
- 9 Viewing jobs
- 10 Restarting stopped jobs
- 11 Scheduling a job
- 12 Remove pending jobs
- 13 Scheduling scripts
- 14 Starting scripts at login
Linux signals
These are the most common Linux system signals:
Num | Name | Job |
1 | SIGHUP | Process hangs up. |
2 | SIGINT | Process Interruption. |
3 | SIGQUIT | Proces quit or stop. |
9 | SIGKILL | Process termination. |
15 | SIGTERM | Process termination. |
17 | SIGSTOP | Process stopping without termination. |
18 | SIGTSTP | Process stopping or pausing without termination. |
19 | SIGCONT | Process continuation after stopping. |
Your Linux bash scripts don’t control these signals. You can program your bash script to recognize signals and perform commands based on the signal that was sent.
Stop a process
To stop a running process, you can press Ctrl+C, which generates a SIGINT signal to stop the current process running in the shell.
$ sleep 100
Ctrl+C
Pause a process
The Ctrl+Z keys generate a SIGTSTP signal to stop any processes running in the shell, and that leaves the program in memory.
$ sleep 100
Ctrl+Z
The number between brackets, which is (1), is the job number.
If you try to exit the shell and you have a stopped job assigned to your shell, the bash warns you if you.
You can use the ps command to view the stopped jobs.
ps –l
In the S column (process state), it shows the traced (T) or stopped (S) states.
If you want to terminate a stopped job, you can kill its process by using the kill command.
kill processID
Trap Signals
To trap signals, you can use the trap command. If the script gets a signal defined by the trap command, it stops processing, and instead, the script handles the signal.
You can trap signals using the trap command like this:
#!/bin/bash trap "echo 'Ctrl-C was trapped'" SIGINT total=1 while [ $total -le 3 ]; do echo "#$total" sleep 2 total=$(($total + 1)) done
Every time you press Ctrl+C, the signal is trapped, and the message is printed.
If you press Ctrl+C, the echo statement specified in the trap command is printed instead of stopping the script. Cool, right?
Trapping the script exit
You can trap the shell script exit using the trap command like this:
#!/bin/bash # Add the EXIT signal to trap it trap "echo Goodbye..." EXIT total=1 while [ $total -le 3 ]; do echo "#$total" sleep 2 total=$(($total + 1)) done
When the bash script exits, the Goodbye message is printed as expected.
Also, if you exit the script before finishing its work, the EXIT trap will be fired.
Modifying or removing a trap
You can reissue the trap command with new options like this:
#!/bin/bash trap "echo 'Ctrl-C is trapped.'" SIGINT total=1 while [ $total -le 3 ]; do echo "Loop #$total" sleep 2 total=$(($total + 1)) done # Trap the SIGINT trap "echo ' The trap changed'" SIGINT total=1 while [ $total -le 3 ]; do echo "Second Loop #$total" sleep 1 total=$(($total + 1)) done
Notice how the script manages the signal after changing the signal trap.
You can also remove a trap by using two dashes.
trap -- SIGNAL
#!/bin/bash trap "echo 'Ctrl-C is trapped.'" SIGINT total=1 while [ $total -le 3 ]; do echo "#$total" sleep 1 total=$(($total + 1)) done trap -- SIGINT echo "I just removed the trap" total=1 while [ $total -le 3 ]; do echo "Loop #2 #$total" sleep 2 total=$(($total + 1)) done
Notice how the script processes the signal before removing the trap and after removing the trap.
$ ./myscript
Crtl+C
The first Ctrl+C was trapped, and the script continues running while the second one exits the script because the trap was removed.
Running Linux Bash scripts in background mode
If you see the output of the ps command, you will see all the running processes in the background and not tied to the terminal.
We can do the same, just place ampersand symbol (&) after the command.
#!/bin/bash total=1 while [ $total -le 3 ]; do sleep 2 total=$(($total + 1)) done
$ ./myscipt &
Once you’ve done that, the script runs in a separate background process on the system, and you can see the process id between the square brackets.
When the script dies, you will see a message on the terminal.
Notice that while the background process is running, you can use your terminal monitor for STDOUT and STDERR messages, so if an error occurs, you will see the error message and normal output.
The background process will exit if you exit your terminal session.
So what if you want to continue running even if you close the terminal?
Running scripts without a hang-up
You can run your Linux bash scripts in the background process even if you exit the terminal session using the nohup command.
The nohup command blocks any SIGHUP signals. It prevents the process from exiting when you exit your terminal.
$ nohup ./myscript &
After running the nohup command, you can’t see any output or error from your script. You sent the output and error messages to a file called nohup.out.
Note: when running multiple commands from the same directory will override the nohup.out file content.
Viewing jobs
To view the current jobs, you can use the jobs command.
#!/bin/bash total=1 while [ $total -le 3 ]; do echo "#$count" sleep 5 total=$(($total + 1)) done
Then run it.
$ ./myscript
Then press Ctrl+Z to stop the script.
Run the same bash script but in the background using the ampersand symbol and redirect the output to a file just for clarification.
$ ./myscript > outfile &
The jobs command shows the stopped and running jobs.
jobs –l
-l parameter to view the process ID
Restarting stopped jobs
You can use the bg command to restart a job in background mode.
$ ./myscript
Then press Ctrl+Z
Now it is stopped.
$ bg
After using the bg command, it is now running in background mode.
If you have multiple stopped jobs, you can do the same by specifying the job number to the bg command.
You can use the fg command to restart a job in foreground mode.
$ fg 1
Scheduling a job
The Linux system provides two ways to run a bash script at a predefined time:
- at command.
- cron table.
The at command
This is the format of the command
at [-f filename] time
The at command can accept different time formats:
- Standard time format like 10:15.
- An AM/PM indicator like 11:15 PM.
- A named time like now, midnight.
You can include a specific date, using some different date formats:
- A standard date format, such as MMDDYY or DD.MM.YY.
- A text date, such as June 10 or Feb 12, with or without the year.
- Now + 25 minutes.
- 05:15 AM tomorrow.
- 11:15 + 7 days.
We don’t want to dig deep into the at command, but for now, just make it simple.
$ at -f ./myscript now
You can use the -M parameter to send the output to email if the system has email, and if not, this will suppress the output of the at command.
To list the pending jobs, use the atq command:
Remove pending jobs
To remove a pending job, use the atrm command:
$ atrm 18
You must specify the job number to the atrm command.
Scheduling scripts
What if you need to run a script at the same time every day or every month or so?
You can use the crontab command to schedule jobs.
To list the scheduled jobs, use the -l parameter:
$ crontab –l
The format for crontab is:
minute,hour, dayofmonth, month, and dayofweek
So if you want to run a command daily at 10:30, type the following:
30 10 * * * command
The wildcard character (*) used to indicate that the cron will execute the command daily on every month at 10:30.
To run a command at 5:30 PM every Tuesday, you would use the following:
30 17 * * 2 command
The day of the week starts from 0 to 6, where Sunday=0 and Saturday=6.
To run a command at 10:00 on the beginning of every month:
00 10 1 * * command
The day of the month is from 1 to 31.
Let’s keep it simple for now, and we will discuss the cron in great detail in future posts.
To edit the cron table, use the -e parameter like this:
crontab –e
Then type your command like the following:
30 10 * * * /home/likegeeks/Desktop/myscript
This will schedule our script to run at 10:30 every day.
Note: sometimes, you see error says Resource temporarily unavailable.
All you have to do is this:
$ rm -f /var/run/crond.pid
You should be a root user to do this.
Just that simple!
You can use one of the pre-configured cron script directories like:
/etc/cron.hourly
/etc/cron.daily
/etc/cron.weekly
/etc/cron.monthly
Just put your bash script file on any of these directories, and it will run periodically.
Starting scripts at login
~/.bashrc – Put your scripts here and it will run every time you open a new terminal.
~/.xprofile – Scripts here will run by the X Window system when you log in to a graphical desktop environment such as GNOME or KDE.
/etc/X11/Xsession.d/ – You can use this directory if you are using a GUI interface in Linux to run your scripts at startup.
/etc/profile – This file contains global environment variables and settings that are applied to all users on the system.
I hope you find the post useful. Keep coming back.
Thank you.
Mokhtar is the founder of LikeGeeks.com. He is a seasoned technologist and accomplished author, with expertise in Linux system administration and Python development. Since 2010, Mokhtar has built an impressive career, transitioning from system administration to Python development in 2015. His work spans large corporations to freelance clients around the globe. Alongside his technical work, Mokhtar has authored some insightful books in his field. Known for his innovative solutions, meticulous attention to detail, and high-quality work, Mokhtar continually seeks new challenges within the dynamic field of technology.
Indentation would be an awesome thing …