📜 ⬆️ ⬇️

Bash scripts, part 10: practical examples

Bash scripts: start
Bash scripts, part 2: loops
Bash scripts, part 3: command line options and keys
Bash scripts, part 4: input and output
Bash Scripts, Part 5: Signals, Background Tasks, Script Management
Bash scripts, part 6: functions and library development
Bash scripts, part 7: sed and word processing
Bash scripts, part 8: awk data processing language
Bash scripts, part 9: regular expressions
Bash scripts, part 10: practical examples
Bash scripts, part 11: expect and automate interactive utilities

In previous articles, we discussed various aspects of the development of bash scripts, talked about useful tools, but so far we have considered only small fragments of code. The time has come for larger projects. Namely, here you will find two examples. The first is a script for sending messages, the second example is a script that displays information about the use of disk space.



The main value of these examples for those who study bash is in the development methodology. When a programmer gets the task of automating anything, his path is rarely direct and fast. The task should be divided into parts, find the means of solving each of the subtasks, and then assemble a ready-made solution from the parts.


')

Sending messages to the user terminal


Nowadays, rarely one resorts to one of the possibilities of Linux, which allows you to communicate by sending messages to the terminals of logged-in users. The write command itself, write , is pretty simple. In order to use it, it is enough to know the username and the name of his terminal. However, in order to successfully send a message, in addition to the actual data about the user and the terminal, you need to know whether the user has logged in and if he has not prohibited entry to his terminal. As a result, several checks need to be performed before sending a message.

As you can see, the task: “send a message”, upon closer inspection, turned out to be a task: “check the possibility of sending a message, and, if there are no obstacles, send it”. Let us deal with the solution of the problem, that is, the development of a bash script.

WhoWho and mesg commands


The core of the script are several commands that we have not yet discussed. Everything else should be familiar to you from previous materials.

The first thing we need here is the who command. It allows you to find out information about users working in the system. In its simplest form, its call looks like this:

 $ who 


The results of the who command

In each line that the who command displays, we are interested in the first two indicators - the name of the user and information about his terminal.

By default, writing to the terminal is allowed, but the user can, with the help of the mesg , prohibit sending messages to him. Thus, before trying to send something to someone, it would be nice to check whether sending messages is allowed. If you need to know your own status, just enter the mesg without parameters:

 $ mesg 


Mesg command

In this case, the team displayed “is y”, which means that the user under which we work in the system can receive messages sent to his terminal. Otherwise, mesg will print “is n”.

To check if sending messages to some other user is allowed, you can use the who command that you already know with the -T switch:

 $ who -T 

However, verification is only possible for users who are logged in. If such a command, after the username, displays a dash (-), this means that the user has prohibited entry to his terminal, that is, messages cannot be sent to him. The fact that the user can send messages, says the plus sign (+).

If your message reception is disabled, and you want to allow other users to send you messages, you can use the following command:

 $ mesg y 


Enabling the reception of messages from other users

After enabling message reception, mesg returns “is y”.
Of course, we need two users to exchange messages, so we, after normal logging in to the system, connected to the computer via ssh. Now you can experiment.

Write write command


The main tool for messaging between logged in users is the write command. If the reception of messages from the user is allowed, using this command, he can send messages using his name and information about the terminal.

Note that using write you can send messages to users logged into the virtual console. Users who work in a graphical environment (KDE, Gnome, Cinnamon, and so on) cannot receive such messages.

So, we, working under the user likegeeks , initiate a communication session with the user testuser , which works in the pts/1 terminal, as follows:

 $ write testuser pts/1 


Checking the possibility of sending messages and sending messages

After executing the above command, we will have an empty line in which you need to enter the first line of the message. By pressing ENTER , we can enter the next line of the message. After the text entry is completed, you can end the communication session using the CTRL + D key combination, which allows you to enter the end-of-file character .

This is what the user to whom we sent the message will see in his terminal.


The new message that came to the terminal

The recipient can understand from whom the message came, see the time when it was sent. Notice the end-of-file flag, EOF , located at the bottom of the terminal window. It indicates the end of the message text.

We believe that now we have everything we need in order to automate the sending of messages using a command line script.

â–Ť Create a script to send messages


Before you send messages, you need to determine whether the user you are interested in logs into the system. You can do this with the following command:

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

Here the results of the who command are passed to the grep . The -i switch of this command allows you to ignore the case of characters. The -m 1 switch is included in the command call in case the user has logged in several times. This command will either not display anything, or will display the user name (we will specify it when the script is called, it will fall into the position variable $1 ) corresponding to the first session found. The output of grep is the awk . This command, again, either does not print anything, or displays an element written to its own variable $1 , that is, the name of the user. As a result, what happened is in the variable logged_on .

Now we need to check the variable l ogged_on , see if there is anything in it:

 if [ -z $logged_on ] then echo "$1 is not logged on." echo "Exit" exit fi 

If you are not quite confident working with the if construct, take a look at this material.
The script containing the above code will be senderscript in the senderscript file and senderscript , giving it, as a command line parameter, the user name testuser .


User status check

Here we check if logged_on variable with zero length. If this is the case, we will be informed that at the moment the user is not logged in and the script will exit using the exit . Otherwise, the script will continue.

â–ŤCheck of recording capabilities in the user terminal


Now you need to check whether the user accepts messages. To do this, we need such a construction, similar to the one we used above:

 allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}') if [ $allowed != "+" ] then echo "$1 does not allowing messaging." echo "Exit" exit fi 


Checking the possibility of sending messages to the user

First we call the who command with the -T switch. In the line of information about the user who can receive messages, there will be a plus sign (+), but if the user cannot receive messages, there will be a dash (-). What happened after calling who is passed to grep , and then awk , forming the variable allowed .

Next, using the conditional operator, we check what is in the allowed variable. If the plus sign is not in it, we will inform you that sending messages to the user is prohibited and finish the work. Otherwise, the script will continue.

â–ŤCheck script validity


The first parameter of the script is the name of the user to whom we want to send a message. The second is the text of the message, in this case - consisting of one word. In order to check whether the message was sent to the script for sending, use the following code:

 if [ -z $2 ] then echo "No message parameter included." echo "Exit" exit fi 


Checking the command line parameters specified when invoking the script

Here, if, when calling the script, the message for sending was not sent to it, we inform about it and finish the work. Otherwise - go ahead.

â–ŤGetting User Terminal Information


Before you send a message to the user, you need to get information about the terminal in which he works and save the terminal name in a variable. This is done like this:

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

Now, after all the necessary data have been collected, it remains only to send a message:

 echo $2 | write $logged_on $terminal 

The call to the finished script looks like this:

 $ ./senderscript testuser welcome 


Successful message sending using bash script

As you can see, everything works as it should. However, using such a script, you can only send messages consisting of one word. It would be nice to be able to send longer messages.

â–ŤSend long messages


Let's try to call the senderscript script, passing a message consisting of several words:

 $ ./senderscript likegeeks welcome to shell scripting 


Attempt to send a long message

As you can see, only the first word was sent. The fact is that each word of the message is perceived inside the script as a separate positional variable. In order to be able to send long messages, we process the command line parameters passed to the script using the shift command and the while .

 shift while [ -n "$1" ] do whole_message=$whole_message' '$1 shift done 

After that, in the message sending command, we use, instead of the previously used positional variable $2 , the variable whole_message :

 echo $whole_message | write $logged_on $terminal 

Here is the full text of the script:

 #!/bin/bash logged_on=$(who | grep -i -m 1 $1 | awk '{print $1}') if [ -z $logged_on ] then echo "$1 is not logged on." echo "Exit" exit fi allowed=$(who -T | grep -i -m 1 $1 | awk '{print $2}') if [ $allowed != "+" ] then echo "$1 does not allowing messaging." echo "Exit" exit fi if [ -z $2 ] then echo "No message parameter included." echo "Exit" exit fi terminal=$(who | grep -i -m 1 $1 | awk '{print $2}') shift while [ -n "$1" ] do whole_message=$whole_message' '$1 shift done echo $whole_message | write $logged_on $terminal 

Test it:

 $ ./senderscript likegeeks welcome to shell scripting 


Successful long message sending:

A long message successfully reached the addressee. Now consider the following example.

Script for monitoring disk space


Now we are going to create a command line script that is designed to search in the specified directories of the top ten folders that account for the most disk space. This will help us team du , which displays information about how much disk space are occupied by files and folders. By default, it displays information only about directories, with the -a option, individual files are -a in the report. Its -s key allows you to display information about the size of directories. This command allows, for example, to find out the amount of disk space that is occupied by the data of a certain user. Here is the call to this command:

 $ du -s /var/log/ 

For our purposes, the -S (capital S) key is better suited, since it allows you to get information both on the root folder and on the directories attached to it:

 $ du -S /var/log/ 


Calling du with the -s and -S options

We need to find the directories that have the most disk space, so the list that du gives out should be sorted using the sort command:

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


Sorted list of objects

The -n switch tells the team to use numeric sorting, the -r — switch to reverse the sort order (the largest number will be at the top of the list). The data obtained is quite suitable for our purposes.

In order to limit the resulting list to the first ten entries, use the stream editor sed , which will remove all rows from the resulting list, starting with the eleventh. The next step is to add its number to each received line. It will also help sed , namely - his team N :

 sed '{11,$D; =}' | sed 'N; s/\n/ /' | 

We put the data in order using awk . Let's pass awk what we got after processing the data with sed , applying, as in other cases, the pipeline, and output the data using the printf command:

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

At the beginning of the line, its number is displayed, then comes a colon and a tab, then the amount of disk space, followed by another tab and the name of the folder.

Putting together all of what we said:

 $ du -S /var/log/ | sort -rn | sed '{11,$D; =}' | sed 'N; s/\n/ /' | awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}' 


Display disk space information

In order to improve the efficiency of the script, the code of which you will very soon see, we implement the possibility of receiving data from several directories at once. To do this, create the variable MY_DIRECTORIES and list the directories of interest to us:

 MY_DIRECTORIES="/home /var/log" 

Enumerate the list using a for loop and call the above sequence of commands for each element of the list. Here is the result:

 #!/bin/bash MY_DIRECTORIES="/home /var/log" echo "Top Ten Disk Space Usage" for DIR in $MY_DIRECTORIES do echo "The $DIR Directory:" du -S $DIR 2>/dev/null | sort -rn | sed '{11,$D; =}' | sed 'N; s/\n/ /' | awk '{printf $1 ":" "\t" $2 "\t" $3 "\n"}' done exit 


Getting information about several directories

As you can see, the script displays, in the form of a convenient list, information about directories, the list of which is stored in MY_DIRECTORIES .

The du command in this script can be invoked with other keys, the resulting list of objects may well be filtered out, in general, there opens up a wide scope for independent experiments. As a result, instead of working with a list of folders, you can, for example, find the largest files with the .log, extension .log, or implement a more complex algorithm for finding the largest (or smallest) files and folders.

Results


Today we have analyzed in detail a couple of script development examples. Here I would like to remind you that our main goal is not to write a script to send messages using the write command, or a script that helps in finding files and folders that take up a lot of disk space, but in describing the development process itself. Having mastered these examples, experimenting with them, perhaps - by adding them or completely reworking, you will learn something new, improve your skills in developing bash scripts.

That's all for today. Next time we will talk about automating the work with interactive utilities using expect.



Dear readers! Do you have in mind simple (and maybe complex, but understandable) bash-scripts, the analysis of which will be useful for beginners?

Source: https://habr.com/ru/post/328346/


All Articles