shell script

How to write practical shell scripts

In the last post, we talked about regular expressions and we saw how to use them in sed and awk for text processing, and we discussed before Linux sed command and awk command. During the series, we wrote small shell scripts, but we didn’t mix things up, I think we should take a small step further and write a useful shell script.

The main reason for learning how to write a shell script is to be able to create your own Linux utilities.

However, the scripts in this post will help you to empower your script writing skills.


Sending messages

You can send messages to someone by phone or email, but one method, not commonly used anymore, is sending a message directly to the user’s terminal.

The shell script that we will build will help you to quickly and easily send a message to someone who is logged into the Linux system.

For this simple shell script, only a few functions are required. Most of the required commands are common and have been covered in our series of shell scripting; you can review the previous posts.

The first needed command is the who command. The who command allows you to see all the users currently logged into the system.

$ who

shell scripts who command

To send a message, you only need the first two items. Both the username and the user’s current terminal.

Users can prevent anyone to send them messages via the mesg command. Therefore, before you start attempting to send messages, you should check whether messages are permitted.

You can enter the mesg command to check is messages are permitted for you or not:

$ mesg

shell scripts mesg command

If the result shows “is y” that means messaging is permitted. If the result shows “is n”, that means messaging is not permitted.

To check anyone else’s message status, use the who command again. Notice that this checks the message status only for those who are currently logged into the system. You can use the -T option to check their message status.

$ who -T

If you see a dash (-) that means messages are turned off and if you see plus sign (+) that means messages are enabled.

To allow messages to be sent to you if it is turned off, you need to use the message command with the “y” option like this:

$ mesg y

shell scripts allow messages

Sure enough, the command shows “is y”, which indicates messages are permitted for this user.

Of course, we need another user to be able to communicate with him so in my case I’m going to connect to my PC using ssh and I’m already logged in with my user, so we have two users logged onto the system.

Now we can send the message from one user to another.

Write command

The primary tool for sending messages between logged in users is the write command. As long as the messaging is permitted, the write command enables you to send a message to another logged-in user using his username and his current terminal.

Note: The write command only allows you to successfully send messages to users who logged onto a virtual console terminal. For those users who logged into the graphical environment (KDE, Gnome, Cinnamon or any) will not be able to receive messages.

We will send a message to testuser user from my user likegeeks like this:

$ write testuser pts/1

shell scripts write command

After the message is started by the write command, a blank line is displayed for you to begin writing the message text.

When the Enter key is pressed, a new line will be available for more message text. After you have finished entering the message text, you can send the message by pressing the Ctrl+D key combination which is the end of file signal. I recommend you to review the post about signals and jobs.

shell scripts receive message

The receiver can recognize which user on which terminal sends the message. A timestamp is also included. Notice the EOF shown at the bottom. It indicates End Of File, which lets the message recipient knows that this is the entire message.

I think now we have all the parts to build our shell script.

Creating the send script

Before we create our shell script, we need to determine whether the user we want to send a message to him is currently logged on the system, this can be done using who command to determine that.

logged_on=$(who | grep -i -m 1 $1 | awk '{print $1}')

The results of the who command are piped into the grep command. The grep command uses the -i option to ignore case. The -m 1 option is included in the grep command, in case the user is logged into the system multiple times.

If the user is not logged on or the username’s first login information, the grep command returns either nothing.

This output is piped to the awk command. The awk command returns only the first item. The final output from the awk command is stored in the variable logged_on.

Then we need to check the variable if it contains something or not:

I recommend you to read the post about the if statement and how to use it Bash Script.

shell scripts check logged user

The logged_on variable is tested to check if it is a zero-length variable.

If it is a zero-length variable, the script prints that the user is not currently logged onto the system, and the script is exited via the exit command.

If the user is logged, the logged_on variable contains the user’s username, and the script continues.

Checking if user accepts messages

The next step is to determine whether a logged on user accepts messages.

shell script check message allowed

Notice that we use the who command with -T. This shows a (+) beside the username if messaging is permitted. Otherwise, it shows a (-) beside the username, if messaging is not permitted.

The results from the who command are then piped into grep and awk to pull out the messaging indicator.

Finally, an if statement is used to test for a messaging indicator. If the indicator is not set to +,the script is exited.

Checking if message was included

To test for the message parameter, an if statement is used like this:

shell script check message

Getting the current terminal

Before we send a message, we need to get the user current terminal and store it in a variable.

terminal=$(who | grep -i -m 1 $1 | awk '{print $2}')

Then we can send the message:

echo $2 | write $logged_on $terminal

Now we can test the whole shell script to see how it goes:

$ ./senderscript likegeeks welcome

Let’s see the other shell window:

shell script send message

Good!  You can now send a simple one-word messages.

Sending a long message

Surely, you want to send more than just a single word. If you try that with this shell script:

$ ./senderscript likegeeks welcome to shell scripting

shell script oneword message

It didn’t work. Only the first word of the message is sent. This is because the script uses parameters and each word is treated as a different parameter.

To fix this problem, we will use the shift command with the while loop.

And now one thing needs to be fixed, which is the message parameter.

Instead of just sending the parameter $2 to the write utility, the script is modified to send the variable, whole_message.

echo $whole_message | write $logged_on $terminal

So now the whole script should be like this:

If you try now:

$ ./senderscript likegeeks welcome to shell scripting

shell script complete message

Awesome!! It worked. Again, I’m not here to make a script to send the message to the user, but the main goal is to review our shell scripting knowledge and use all the parts we’ve learned together and see how things work together.

Monitoring Disk Space

We are going to build a shell script utility that will help you to determine the top ten disk space consumers for designated directories.

The du command displays the disk usage for individual files and directories. The -s option enables you to summarize totals at the directory level.

This is useful when calculating the total disk space used by an individual user.

$ du -s /var/log/

The -S (capital S) option works great for our purposes here, it provides the total for each directory and subdirectory individually.

$ du -S /var/log/

shell script du command

Because we are interested in the directories consuming the biggest chunks of disk space, the sort command is used with the result produced by du command like this:

$ du -S /var/log/ | sort -rn

shell script sort command

The -n option enables you to sort numerically. The -r option lists the highest numbers first.

To get the top ten disk space usage users, when line 11 is reached, sed is used to delete the rest of the listing.

The next step is to add a line number for each line in the listing. To get those line numbers on the same line as the disk space text, use the N command like this:

Then we can clean the output using the awk command. The output from the sed command is piped into the awk command and printed using the printf function:

awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}'

After the line number, a colon (:) and tab (\t) characters are inserted between the individual fields in each text line’s output row.

shell script format output with sed and awk

To be productive, the script creates a report for multiple directories. Suppose we have a variable called  MY_DIRECTORIES, and the variable is set to just two directories.

MY_DIRECTORIES=”/home /var/log”

We will make a for loop to perform the du command on each directory listed in the variable. Each time the for loop iterates through the list of values in the variable MY_DIRECTORIES.

So the shell script will look like this:

shell script monitor disk usage

Good!! The report shows the disk consumption for both directories in a beautifully formatted report.

You can filter files, so instead of calculating the consumption of all files, you can calculate the consumption for a specific extension like *.log or whatever.

One thing I have to mention here, in production systems, you can’t rely on disk space report instead, consider setting disk quotas. If the quota package is installed.

Quota package is specialized for that, but here we are learning how bash scripts work.

Again the shell scripts we’ve introduced here is for showing you how shell scripting work, there are a ton of ways to implement any task in Linux.

My post is finished for now. I tried to reduce the post length and make everything simple as possible, hope you like it.

Thank you.