Messages can be sent in many ways in an office or a home environment — text message, e-mail, and even making a phone call. One method, not commonly used any more, is sending a message directly to a fellow system user's terminal. Because this technique is largely unknown, it can be fun to communicate with someone with this method.
This shell script utility helps you to quickly and easily send a message to someone who is logged onto your Linux system. It is a rather simple script, but it can be loads of fun!
For this simple script, only a few functions are required. Several of the commands are common and have been covered in the book. However, a few of the commands have only been touched on, and you may not be familiar with the primary command needed. This section looks at the commands needed to put together this simple, but interesting script.
The first utility needed is the who
command. The who
utility allows you to see all the users currently logged into the system:
$ who
christine tty2 2015-09-10 11:43
timothy tty3 2015-09-10 11:46
[...]
$
In this partial listing, all the information needed for sending messages is shown. By default, the who
command gives you the short version of information available. The same information is provided, when who -s
is issued:
To send a message, you only need the first two items. Both the user name and the user's current terminal are necessary.
Users can disallow anyone to send them messages via the mesg
utility. Therefore, before you start attempting to send messages, it's a good idea to check whether messages are allowed. For yourself, you can simply enter the mesg
command as follows:
$ mesg
is n
$
The is n
result shows that messaging is turned off. If the result showed is y
, messages would be allowed.
To check everyone else's message status, you can use the who
command again. Keep in mind that this checks the message status only for those who are currently logged into the system. You use the -T
option to check their message status:
$ who -T
christine -
tty2 2015-09-10 12:56
timothy -
tty3 2015-09-10 11:46
[...]
$
The dash (-
) after each user name indicates that messaging is turned off for those users. If it is turned on, you see a plus (+
) sign.
To allow messages to be sent to you, if it is turned off, you need to use the message command with the y
option:
$ whoami
christine
$
$ mesg y
$
$ mesg
is y
$
Messaging is turned on by the user christine
, when the command mesg y
is issued. The user's individual message status is checked, by issuing the mesg
command. Sure enough, the command shows is y
, which indicates messages are allowed to this user.
Using the who
command, other users can see how the user christine
has changed her message status. The message status is now set to a plus sign, which indicates the user is allowing messages to be sent to her.
$ who -T
christine +
tty2 2015-09-10 12:56
timothy - tty3 2015-09-10 11:46
[...]
$
For two-way communication, you need to allow messaging and one or more users also need to allow messaging. In this example, the user timothy
has also turned on his messaging:
$ who -T
christine + tty2 2015-09-10 12:56
timothy +
tty3 2015-09-10 11:46
[...]
$
Now that messaging is allowed between you and at least one other user, you can try out the command to send messages. However, the who
command is also still needed, because it provides the necessary information in order to send a message.
The primary tool for this script is the write
command. As long as messaging is allowed, the write
command allows you to send a message to another logged-in user using his username and current terminal.
In this example, a message is sent from user christine
to user timothy
logged on the tty3 terminal. From christine
's terminal, the session looks as follows:
$ who
christine tty2 2015-09-10 13:54
timothy
tty3
2015-09-10 11:46
[...]
$
$ write timothy tty3
Hello Tim!
$
After the message is initiated by the write
command, a blank line is shown for you to begin inputting the message text. It may be as many lines as you desire. When the Enter key is pressed, a new line is available for more message text. After you are finished entering message text, the whole message is sent by pressing the Ctrl+D key combination.
The receiver of the message sees something like the following:
Message from christine@server01 on tty2 at 14:11 ...
Hello Tim!
EOF
The receiver can see which user on which terminal sent the message. A time stamp is also included. Notice the EOF
shown at the message's bottom. It indicates End Of File, which lets the message recipient know that the entire message is being displayed.
Now you can send messages! The next step is to use these commands to create the script.
Using a script to send messages helps overcome a few potential problems. First, if you have lots of users on the system, trying to find the one user you want to send a message to can be a pain! You must also determine whether that particular user has messaging turned on. In addition, a script speeds things up allowing you to quickly send a message to a particular user in one easy step.
The first issue is to let the script know to which user you want to send a message. This is easily done by sending a parameter (Chapter 14) along with the script's execution. For the script to determine whether that particular user is logged on the system, the who
command is employed as shown in this bit of script code:
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $1 | gawk '{print $1}')
#
In the preceding code, the results of the who
command are piped into the grep
command (Chapter 4). The grep
command uses the -i
option to ignore case, which allows the username to be entered using uppercase or lowercase letters. The -m 1
option is included on the grep
command, in case the user is logged into the system multiple times. The grep
command produces either nothing, if the user is not logged on, or the username's first login information. This output is passed to the gawk
command (Chapter 19). The gawk
command returns only the first item, either nothing or the username. This final output from the gawk
command is stored in the variable logged_on
.
When the variable, logged_on
, contains either nothing (if the user is not logged on) or the username, it can be tested and acted upon:
#
if [ -z $logged_on ]
then
echo "$1 is not logged on."
echo "Exiting script..."
exit
fi
#
Employing the use of an if
statement and a test
command (Chapter 12), the logged_on
variable is tested to determine if it is a zero-length variable. If it is a zero-length variable, the script user is informed via echo
commands that the user is not currently logged onto the system, and the script is exited via the exit
command. If the user is logged onto the system, the logged_on
variable contains the user's username, and the script continues.
In the following example, a username, Charlie
, is passed as a parameter to the shell script. This user is not currently logged onto the system:
$ ./mu.sh Charlie
Charlie is not logged on.
Exiting script...
$
The code worked perfectly! Now instead of you digging through the who
command results to determine whether a user is logged onto the system, the message script does that for you.
The next important item is to determine whether a logged on user accepts messages. This script portion operates very closely to the script section for determining whether a user is logged on:
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $1 | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
echo "$1 does not allowing messaging."
echo "Exiting script..."
exit
fi
#
Notice that this time, the who -T
command and option are used. This displays a +
next to the username, if messaging is allowed. Otherwise, it displays a -
next to the username, if messaging is not allowed. The results from the who
command are then piped into grep
and gawk
to pull out only the messaging indicator. The messaging indicator is stored in the allowed
variable. Finally, an if
statement is employed to test for a messaging indicator not set to +
. If the indicator is not set to +
, the script user is informed and the script is exited. However, if the messaging indicator shows messaging is allowed, the script continues.
To test out this script's section, a user who is logged into the system with messaging disabled is tested. The user Samantha
currently has messaging disabled:
$ ./mu.sh Samantha
Samantha does not allowing messaging.
Exiting script...
$
The test worked as expected. This script portion eliminates any need to manually check for messaging being enabled or disabled.
The message to be sent is also included as a script parameter. Therefore, another needed check is whether a message was included as a parameter to the mu.sh
shell script. To test for the message parameter, an if
statement, similar to those used earlier, must be included in the script's code:
# Determine if a message was included:
#
if [ -z $2 ]
then
echo "No message parameter included."
echo "Exiting script..."
exit
fi
#
To test out this script portion, a message was not included for a user who is both logged into the system and allows messaging:
$ ./mu.sh Timothy
No message parameter included.
Exiting script...
$
This is exactly what is needed! Now that the script has performed these preliminary checks, the primary task of sending a message can be undertaken.
Before a message is sent, the user's current terminal must be identified and stored in a variable. The who
, grep
, and gawk
commands are employed again:
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $1 | gawk '{print $2}')
#
To transmit the message, both the echo
and the write
commands are used:
#
echo $2 | write $logged_on $uterminal
#
Because write
is an interactive utility, it must have the message piped into it for the script to work properly. The echo
command is used to send the message, $2, to STDOUT
, which in turn is piped into the write
command. The logged_on
variable holds the username, and the uterminal
variable holds the user's current terminal.
Now, you can test sending a simple message to a designated user via the script:
$ ./mu.sh Timothy test
$
The user Timothy
receives the following message on his terminal:
Message from christine@server01 on tty2 at 10:23 ...
test
EOF
Success! You can now send simple one word messages to other users on your system via your script.
Often, you want to send more than just a single word to another system user. Let's try a longer message using the current script:
$ ./mu.sh Timothy Boss is coming. Look busy.
$
The user Timothy
receives the following message on his terminal:
Message from christine@server01 on tty2 at 10:24 ...
Boss
EOF
It didn't work. Only the first word of the message, Boss
, was sent. This is due to the script using parameters (Chapter 14). Recall that the bash shell considers a space to differentiate between parameters. Thus, because there are spaces in the message, each word is treated as a different parameter. The script must be modified to fix this problem.
The shift
command (Chapter 14) and a while
loop (Chapter 13) help with this long message issue:
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
whole_message=$whole_message' '$1
shift
done
#
Recall that the shift
command allows you to process the various provided script parameters without knowing the total number of parameters. The shift
command simply moves the next parameter in line down to parameter $1
. First, a primary shift
must be issued before the while
loop, because the message starts in parameter $2
, instead of parameter $1
.
After the while
loop is initiated, it continues grabbing each message word, tacking the word onto the whole_message
variable. The loop then shifts to the next parameter. After the final parameter is processed, the while
loop exits and the whole_message
variable contains the entire message to send.
One additional script modification is needed to fix this problem. Instead of just sending parameter $2
to the write
utility, the script is modified to send the variable, whole_message
:
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $1 | gawk '{print $2}')
#
echo $whole_message
| write $logged_on $uterminal
#
Now, again try to send that warning message about the boss coming his way to Timothy
:
$ ./mu.sh Timothy Boss is coming
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
$
Oops! That didn't work either. This is because when shift
was used in the script, the $1
parameter contents were removed. Thus, when the script attempts to use $1
in the grep
command, it generates an error. To fix this problem a variable, muser
, is used to capture the $1
parameter's value:
# Save the username parameter
#
muser=$1
#
Now muser
stores the username. The $1
parameter in the script's various grep
and echo
commands can be replaced by the muser
variable:
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser
| gawk '{print $1}')
[...]
echo "$muser
is not logged on."
[...]
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser
| gawk '{print $2}')
[...]
echo "$muser
does not allowing messaging."
[...]
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser
| gawk '{print $2}')
[...]
To test out the script changes, a multi-word message is sent again. In addition, some emphasis is added to the message by tacking on exclamation points:
$ ./mu.sh Timothy The boss is coming! Look busy!
$
The user Timothy
receives the following message on his terminal:
Message from christine@server01 on tty2 at 10:30 ...
The boss is coming! Look busy!
EOF
It worked! You can now employ the script to quickly send messages to other users on the system. Here's the final message script with all the needed checks and changes:
#!/bin/bash
#
#mu.sh - Send a Message to a particular user
#############################################
#
# Save the username parameter
#
muser=$1
#
# Determine if user is logged on:
#
logged_on=$(who | grep -i -m 1 $muser | gawk '{print $1}')
#
if [ -z $logged_on ]
then
echo "$muser is not logged on."
echo "Exiting script..."
exit
fi
#
# Determine if user allows messaging:
#
allowed=$(who -T | grep -i -m 1 $muser | gawk '{print $2}')
#
if [ $allowed != "+" ]
then
echo "$muser does not allowing messaging."
echo "Exiting script..."
exit
fi
#
# Determine if a message was included:
#
if [ -z $2 ]
then
echo "No message parameter included."
echo "Exiting script..."
exit
fi
#
# Determine if there is more to the message:
#
shift
#
while [ -n "$1" ]
do
whole_message=$whole_message' '$1
shift
done
#
# Send message to user:
#
uterminal=$(who | grep -i -m 1 $muser | gawk '{print $2}')
#
echo $whole_message | write $logged_on $uterminal
#
exit
Because you have made it to the last chapter in this book, you should be ready for a script-writing challenge. Here are some suggested improvements for the message script that you can attempt on your own:
write
commands.)write
command can only write to virtual console terminals.)cat
command output piped into the write
utility, instead of the echo
command.)Not only does reading through the script help solidify the script-writing concepts you are learning, but so does modifying the script. Come up with your own creative modification. Have a little fun! It helps you learn.
Inspirational quotes have long been used in the business environment. You may have a few on your office wall right now. This fun little and interesting script helps you obtain a daily inspirational quote to use as you please.
This section takes you through how to create this script. Included is a new rich utility that has not been covered in the book yet. The script also uses some utilities that have been covered, such as sed
and gawk
.
Several great websites allow you to obtain daily inspiration quotes. Just open your favorite search engine, and you can find many sites. After you find a site for your daily quote, you need a utility to download that quote. For this script, the wget
utility is just what's needed.
The wget
utility is a flexible tool that allows web pages to be downloaded to your local Linux system. From these pages, you can glean your daily inspirational quote.
To download a web page via wget
, you just need the wget
command and the website's address:
$ wget www.quotationspage.com/qotd.html
--2015-09-23 09:14:28-- http://www.quotationspage.com/qotd.html
Resolving www.quotationspage.com... 67.228.101.64
Connecting to www.quotationspage.com|67.228.101.64|:80. connected
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: "qotd.html"
[ <=> ] 13,806 --.-K/s in 0.1s
2015-09-23 09:14:28 (118 KB/s) - "qotd.html" saved [13806]
$
The website's information is stored in a file named after the web page. In this case, it's qotd.html
. And as you might have guessed by now, the file is full of HTML code:
$ cat qotd.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns:fb="http://ogp.me/ns/fb#">
<head>
<title type="main">Quotes of the Day - The Quotations Page</title>
[...]
Only a partial HTML code listing is shown here. For the script, the sed
and gawk
utilities help strip out the desired inspirational quote. But before tackling the script, you need a little more control over the wget
utility's input and output.
You can use a variable to hold the web address (URL). Simply pass the variable to wget
as a parameter. Just don't forget to use the $
along with the variable name:
$ url=www.quotationspage.com/qotd.html
$
$ wget $url
--2015-09-23 09:24:21-- http://www.quotationspage.com/qotd.html
Resolving www.quotationspage.com... 67.228.101.64
Connecting to www.quotationspage.com|67.228.101.64|:80 connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: "qotd.html.3"
[ <=> ] 13,806 --.-K/s in 0.1s
2015-09-23 09:24:21 (98.6 KB/s) - "qotd.html.3" saved [13806]
$
The daily inspiration quote script is eventually to be run daily via cron
(Chapter 16) or some other script automation utility. Thus, having the wget
command's session output display to STDOUT
is undesirable. To store the session output to a log file, use the option -o
. This allows session output to be viewed at a later time:
$ url=www.quotationspage.com/qotd.html
$
$ wget -o quote.log $url
$
$ cat quote.log
--2015-09-23 09:41:46-- http://www.quotationspage.com/qotd.html
Resolving www.quotationspage.com... 67.228.101.64
Connecting to www.quotationspage.com|67.228.101.64|:80 connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: "qotd.html.1"
0K .......... ... 81.7K=0.2s
2015-09-23 09:41:46 (81.7 KB/s) - "qotd.html.1" saved [13806]
$
The wget
utility now stores its session output into the log file as it retrieves web page information. If desired, you can view the logged session output by using the cat
command, as shown in the preceding code.
To control where the web page information is stored, use the -O
option on the wget
command. Thus, instead of having the web address as the storage file name, you can use the filename of your choice:
$ url=www.quotationspage.com/qotd.html
$
$ wget -o quote.log -O Daily_Quote.html $url
$
$ cat Daily_Quote.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns:fb="http://ogp.me/ns/fb#">
<head>
[...]
$
Using the -O
option allows the web page data to be stored in the designated file, Daily_Quote.html
. Now that the wget
utility's output is controlled, the next required function, checking the web address's validity, can be explored.
Web addresses change. Sometimes, it seems this happens daily. Therefore, it is important to test the address validity within the script. The wget
utility gives the ability to conduct such a test with the --spider
option:
$ url=www.quotationspage.com/qotd.html
$
$ wget --spider $url
Spider mode enabled. Check if remote file exists.
--2015-09-23 12:45:41-- http://www.quotationspage.com/qotd.html
Resolving www.quotationspage.com... 67.228.101.64
Connecting to www.quotationspage.com|67.228.101.64|:80 connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Remote file exists and could contain further links,
but recursion is disabled -- not retrieving.
$
This output indicates that the URL is valid, but it's too much to read through. You can cut down on the output by adding the -nv
option, which stands for non-verbose:
$ wget -nv --spider $url
2015-09-23 12:49:13
URL: http://www.quotationspage.com/qotd.html 200 OK
$
The -nv
option allows just the web address's status to be displayed, making the output much easier to read. Contrary to what you may think, the OK
at the non-verbose line's end does not indicate that the web address is valid. The indication is that the web address came back as it was sent. This concept is a little unclear, until you see an invalid web address.
To see an invalid web address indicator, the URL
variable is changed to an incorrect web address. The wget
command is reissued using this bad address:
$ url=www.quotationspage.com/BAD_URL.html
$
$ wget -nv --spider $url
2015-09-23 12:54:33
URL: http://www.quotationspage.com/error404.html 200 OK
$
Notice that the output still has an OK
at its end. However, the web address ends in error404.html
. This indicates the web address is invalid.
With the necessary wget
command to grab the inspirational quote's web page information, and the ability to test the web page's address, it is time to start building the script. Your daily inspirational quote awaits retrieval.
To test the script as it is built, a parameter containing the website's URL is passed to the script. Within the script, the variable quote_url
contains the passed parameter's value:
#
quote_url=$1
#
It is always a good idea to have checks in place within your script. The first check is to ensure that the daily inspirational quote script website's URL is still valid.
As you would expect, the script checks the web address validity with wget
and the --spider
option. However, the resulting indicator must be saved so the indicator can be checked later with an if
statement test. Thus, the resulting indicator must be saved to a variable. This is a little tricky with the wget
command.
To save the indicator output, the standard $()
syntax is used around the command. But in addition, STDERR
and STDOUT
redirection is needed. This is accomplished by tacking on 2>&1
to the end of the wget
command:
#
check_url=$(wget -nv --spider $quote_url 2>&1)
#
Now the indicator status message is saved within the check_url
variable. To carve out the error indicator, error404
, from the check_url
string, parameter expansion and the echo
command can be used:
#
bad_url=$(echo ${check_url/*error404*/error404})
#
In this example, string parameter expansion allows the string stored in check_url
to be searched. Think of string parameter expansion as a quick and easy sed
alternative. Using wildcards around the search word, *error404*
allows the entire string to be searched. If the search is successful, the echo
command sends the string error404
to be stored into the bad_url
variable. If the search is not successful, the bad_url
variable contains the check_url
variable's contents.
Now an if
statement (Chapter 12) is employed to check the bad_url
variable's string. If the string error404
is found, a message is displayed and the script exits:
#
if [ "$bad_url" = "error404" ]
then
echo "Bad web address"
echo "$quote_url invalid"
echo "Exiting script..."
exit
fi
#
An easier and shorter method can be used. This method removes the need for string parameter expansion and the bad_url
variable altogether. A double bracket if
statement allows a search to be conducted of the check_url
variable:
if [[ $check_url == *error404* ]]
then
echo "Bad web address"
echo "$quote_url invalid"
echo "Exiting script..."
exit
fi
The test statement within the if
structure searches the check_url
variable's string. If the string error404
is found anywhere within the variable string, a message is displayed and the script exits. If the indicator string does not contain the error message, the script continues. This statement saves time and effort. No need for any string parameter expansion or even the bad_url
variable.
Now that the check is in place, the script can be tested with an invalid web address. The url
variable is set to an incorrect URL and passed to the get_quote.sh
script:
$ url=www.quotationspage.com/BAD_URL.html
$
$ ./get_quote.sh $url
Bad web address
www.quotationspage.com/BAD_URL.html invalid
Exiting script...
$
That works great. Just to make sure that all is well, now a valid web address is tested:
$ url=www.quotationspage.com/qotd.html
$
$ ./get_quote.sh $url
$
No error message received. The script works perfectly so far! This is the only check needed, so the next item to be added to the script is obtaining the web page's data.
Grabbing the inspiration daily quote's web page data is simple. The wget
command shown earlier in the chapter is used in the script. The only needed change is to store the log file and the HTML file, which contains the web page information, in the /tmp
directory:
#
wget -o /tmp/quote.log -O /tmp/quote.html $quote_url
#
Before moving on to the rest of the script, this code section should be tested using a valid web address:
$ url=www.quotationspage.com/qotd.html
$
$ ./get_quote.sh $url
$
$ ls /tmp/quote.*
/tmp/quote.log /tmp/quote.html
$
$ cat /tmp/quote.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns:fb="http://ogp.me/ns/fb#">
<head>
[...]
</body>
</html>
$
The script still works well! The log file, /tmp/quote.log
, and the html file, /tmp/quote.html
, were properly created.
The next task is to dig the daily inspirational quote out of the HTML code within the downloaded web page HTML file. This task requires both the sed
and the gawk
utilities.
In order to pull out the actual inspirational quote, some processing must take place. This part of the script uses sed
and gawk
to parse out the desired information.
The script first needs to remove all the HTML tags from the downloaded web page's information stored in the /tmp/quote.html
file. The sed
utility can provide this capability:
#
sed 's/<[∧>]*//g' /tmp/quote.html
#
The preceding code should look very familiar. It was covered in Chapter 21 in the “Removing HTML tags” section.
After the HTML tags are removed, the output looks like the following:
$ url=www.quotationspage.com/qotd.html
$
$ ./get_quote.sh $url
[...]
>Quotes of the Day - The Quotations Page>
>
[...]
>>Selected from Michael Moncur's Collection of Quotations
- September 23, 2015>>
>>>Horse sense is the thing a horse has which keeps
[...]
>
$
This snipped listing shows that there is still too much unnecessary data in this file. Therefore, some additional parsing must be done. Fortunately, the quote text needed is situated right next to the current date. Therefore, the script can use the current date as a search term!
The grep
command, the $()
format, and the date
command can help here. The output from the sed
command is piped into the grep
command. The grep
command uses the current date formatted to match the date used on the quotation's web page. After the date text line is found, two additional text lines are pulled with the -A2
parameter:
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2
#
Now the script's output looks similar to the following:
$ ./get_quote.sh $url
>>Selected from Michael Moncur's Collection of Quotations
- September 23, 2015>>
>>>Horse sense is the thing a horse has which keeps it from
betting on people.> >>>>>>>>>>>>>>>>>>W. C. Fields> (1880 -
1946)> >>>
>>Newspapermen learn to call a murderer 'an alleged murderer'
and the King of England 'the alleged King of England' to
avoid libel suits.> >>>>>>>>>>>>>>>>>>Stephen Leacock> (1869
- 1944)> >>> - More quotations on: [>Journalism>] >
$
Although the output is greatly reduced, there is still too much clutter in the text. The extra >
symbols can easily be removed with the sed
utility. In the script, the output from the grep
command is piped into the sed
utility, which strips off the >
symbols:
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2 |
sed 's/>//g'
#
With the new script line, the output is now a little clearer:
$ ./get_quote.sh $url
Selected from Michael Moncur's Collection of Quotations
- September 23, 2015
Horse sense is the thing a horse has which keeps it from
betting on people. W. C. Fields (1880 - 1946)
Newspapermen learn to call a murderer 'an alleged murderer'
and the King of England 'the alleged King of England' to
avoid libel suits. Stephen Leacock (1869 - 1944) -
More quotations on: [Journalism]
$
Now we're getting somewhere! However, we can still remove a little more clutter from the quotation.
You may have noticed that two quotations are listed in the output instead of one. This happens occasionally with this particular website. Some days, it may be one quote, and other days, it may be two. Therefore, the script needs a way to pull out only the first quote.
The sed
utility can help again with this problem. Using the sed
utility's next and delete
commands (Chapter 21), the string
is located. After it's found, sed
moves to the next line of the data and deletes it:
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2 |
sed 's/>//g' |
sed '/ /{n ; d}'
#
Now the script can be tested to see if the new sed
addition fixes the multiple quotation problem:
$ ./get_quote.sh $url
Selected from Michael Moncur's Collection of Quotations
- September 23, 2015
Horse sense is the thing a horse has which keeps it from
betting on people. W. C. Fields (1880 - 1946)
$
The extra quotation is removed! One item remains for the quotation cleanup. At the quotation's end, the string
is still hanging around. The script could use another sed
command to remove this pesky item, but just for variety, the gawk
command is used:
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2 |
sed 's/>//g' |
sed '/ /{n ; d}' |
gawk 'BEGIN{FS=" "} {print $1}'
#
In the preceding code, the input field separator variable, FS
, is used with the gawk
command (Chapter 22). The string
is set as a field separator, which causes gawk
to drop it from the output:
$ ./get_quote.sh $url
Selected from Michael Moncur's Collection of Quotations
- September 23, 2015
Horse sense is the thing a horse has which keeps it from
betting on people. W. C. Fields (1880 - 1946)
$
One last needed script action is to save this quotation text to a file. Here the tee
command (Chapter 15) helps. Now the entire quote extraction process looks as follows:
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2 |
sed 's/>//g' |
sed '/ /{n ; d}' |
gawk 'BEGIN{FS=" "} {print $1}' |
tee /tmp/daily_quote.txt > /dev/null
#
The extracted quote is saved to /tmp/daily_quote.txt
, and any output produced by the gawk
command is redirected to /dev/null
(see Chapter 15). To make the script a little more self-directed, the URL is hard-coded into the script:
#
quote_url=www.quotationspage.com/qotd.html
#
Now these two new changes to the daily inspirational quote script can be tested:
$ ./get_quote.sh
$
$ cat /tmp/daily_quote.txt
Selected from Michael Moncur's Collection of Quotations
- September 23, 2015
Horse sense is the thing a horse has which keeps it from
betting on people. W. C. Fields (1880 - 1946)
$
That works perfectly! The daily inspiration quote was extracted from the website's data and stored in a text file. You may have noticed by now that this quotation is less a traditional inspirational quote and more a humorous quote. Just know that some people find humor inspirational!
For your review, here's the final daily inspirational quote script with all the needed checks and changes:
#!/bin/bash
#
# Get a Daily Inspirational Quote
#####################################
#
# Script Variables ####
#
quote_url=www.quotationspage.com/qotd.html
#
# Check url validity ###
#
check_url=$(wget -nv --spider $quote_url 2>&1)
#
if [[ $check_url == *error404* ]]
then
echo "Bad web address"
echo "$quote_url invalid"
echo "Exiting script..."
exit
fi
#
# Download Web Site's Information
#
wget -o /tmp/quote.log -O /tmp/quote.html $quote_url
#
# Extract the Desired Data
#
sed 's/<[∧>]*//g' /tmp/quote.html |
grep "$(date +%B' '%-d,' '%Y)" -A2 |
sed 's/>//g' |
sed '/ /{n ; d}' |
gawk 'BEGIN{FS=" "} {print $1}' |
tee /tmp/daily_quote.txt > /dev/null
#
exit
This script is an excellent opportunity to try out some of your newly learned script writing and command line skills. The following are a few suggested changes for the daily inspirational quote script that you can attempt on your own:
sed
and gawk
commands for extracting the daily quotation.cron
(see Chapter 16).Reading your daily quotes can inspire you. They may just inspire you to get out of that next business meeting. The next chapter section helps you write a script that does just that.
You've been there. That endless staff meeting that is full of unimportant information. You would really rather be working on that fascinating bash shell script project back at your desk. Here's a little fun script you can use to get out of the next staff meeting.
Short Message Service (SMS) allows text messages to be sent between cell phones. However, you can also use SMS to send text messages directly from e-mail or the command line. The script in this section allows you to construct a text message to be sent at a specified time directly to your phone. Receiving a “critical” message from your Linux system is the perfect excuse for leaving a staff meeting early.
You can send an SMS message from the command line in several ways. One way is via your system's e-mail using your phone carrier's SMS service. Another way is using the curl
utility.
Similar to wget
, the curl
utility allows you to transfer data from a particular web server. Unlike wget
, it also allows you to transfer data to a web server. Transferring data to a particular web server is exactly what is needed here.
Besides the curl
utility, you need a website that provides free SMS message transfer. The one used here for this script is http://textbelt.com/text. This website allows you to send up to 75 text messages per day for free. You need it only for one text message, so it should be no problem.
To use curl
and http://textbelt.com/text to send yourself a text message, you need to use the following syntax:
$ curl http://textbelt.com/text \
-d number=YourPhoneNumber
\
-d "message=Your Text Message
"
The -d
option tells curl
to send specified data to the website. In this case, the website needs particular data sent in order to send a text message. This data includes YourPhoneNumber
, which is your cell phone number starting with the area code. And it also includes Your Text Message
, which is the text message you desire to send.
When the message is sent, the website provides a success message, ”success”: true
, if no problems occurred:
$ curl http://textbelt.com/text \
> -d number=3173334444 \
> -d "message=Test from curl"
{
"success": true
}$
$
Or it provides a fail message, ”success”: false
, if data, such as the phone number, is incorrect:
$ curl http://textbelt.com/text \
-d number=317AAABBBB \
-d "message=Test from curl"
{
"success": false,
"message": "Invalid phone number."
}$
$
The success/fail messages are very helpful, but they are unwanted for the script. To remove these messages, simply redirect STDOUT
to /dev/null
(see Chapter 15). Unfortunately, now curl
supplies undesired output:
$ curl http://textbelt.com/text \
> -d number=3173334444 \
> -d "message=Test from curl" > /dev/null
% Total % Received % Xferd Average Speed...
Dload Upload...
0 21 0 21 0 45 27 58 ...
$
The preceding snipped listing shows various statistics, which may be helpful when debugging your curl
command. However, for the script, this information must be suppressed. Fortunately, the curl
command has a -s
option, which makes it silent:
$ curl -s http://textbelt.com/text \
> -d number=3173334444 \
> -d "message=Test from curl" > /dev/null
That is much better. The curl
command is ready to be put into a script. However, before looking at the script, one more topic needs to be addressed: sending text messages via e-mail.
If you choose not to use the text message relay service provided by http://textbelt.com/text or if for some reason it doesn't work for you, you can always substitute sending a text message via e-mail. This section briefly covers how to accomplish this substitution.
Whether or not e-mail works as a substitute depends upon your cell phone carrier. If your cell phone carrier has an SMS gateway, you are in luck. Contact your cell phone carrier and find out the name of the gateway. Often, it is something similar to txt.att.net
or vtext.com
.
The basic syntax for sending a text message via e-mail is as follows:
mail -s "
your text message
"
your_phone_number@your_sms_gateway
Unfortunately, after you enter the syntax, you must type your message and press Ctrl+D to send the text message. This is similar to sending a regular e-mail (see Chapter 24). Using this method doesn't work well in a script. Instead, you can store your e-mail message in a file and use it to send a text message. The basic idea for this method is as follows:
$ echo "This is a test" > message.txt
$ mail -s "Test from email" \
3173334444@vtext.com < message.txt
Now the e-mail syntax is more compatible with a script. However, be aware that many problems may exist with this approach. First, you must have a mail server running on your system (see Chapter 24). Secondly, your phone service provider may block SMS messages coming from your system via e-mail. This is often true, if you are attempting this method from your home.
Although sending a text message via e-mail is a potential alternative, it can be fraught with problems. If you can, it is much easier to use a free SMS relay website and the curl
utility. The script in the next section uses curl
to send a text message to the phone of your choice.
After you have the required functions, creating the script to send a text message is fairly simple. You just need a few variables and the curl
command.
You need three variables for the script. Setting up these particular data items as variables makes it easier if any of this information changes. The variables are shown here:
#
phone="3173334444"
SMSrelay_url=http://textbelt.com/text
text_message="System Code Red"
#
The only other needed item is the curl
utility. Thus, here is the entire send a text message script:
#!/bin/bash
#
# Send a Text Message
################################
#
# Script Variables ####
#
phone="3173334444"
SMSrelay_url=http://textbelt.com/text
text_message="System Code Red"
#
# Send text ###########
#
curl -s $SMSrelay_url -d \
number=$phone \
-d "message=$text_message" > /dev/null
#
exit
If you see this script as simple and easy, you are right! Even more important, that means you have learned a great deal about shell script writing. Even easy scripts need to be tested, so be sure to test this script using your cell phone number in the phone
variable before continuing.
To have a text message sent to you at a desired time, you must employ the at
command. If you need a reminder, the at
command was covered in Chapter 16.
First, you can test the use of the at
command with your new script. Have the at
utility execute the script by using the -f
option along with the script's file name, send_text.sh
, in this case. Have the script run immediately using the Now
option:
$ at -f send_text.sh Now
job 22 at 2015-09-24 10:22
$
The script runs instantly. However, it may be a minute or two before you receive the text message on your phone.
To have the script run at another time, you simply use other at
command options (see Chapter 16). In the following example, the script is run 25 minutes from the current time.
$ at -f send_text.sh Now + 25 minutes
job 23 at 2015-09-24 10:48
$
Note in the example, the at
command provides an informational message when the script is submitted. The date and time listed in that message is when the script will execute.
What fun! Now you have a script utility that will be of assistance when you need an excuse to get out of that staff meeting. Better yet, you could modify the script to send yourself truly serious system messages that need to be addressed.
This chapter showed how to put some of the shell-scripting information presented in the book to use for fun little shell scripts. Each script reinforced material covered in the chapters along with a few new commands and ideas.
The chapter demonstrated how to send a message to another user on the Linux system. The script checked to see whether the user was logged on to the system and whether the user allowed messaging. After those checks were made, the passed message was sent using the write
command. Included were some suggestions for modifying this script, which improve your shell-scripting abilities.
The next section walked you through obtaining website information using the wget
utility. The created script pulled a quote from the web. After retrieval, the script used several utilities to pull out the actual quote text. These now familiar commands included sed
, grep
, gawk
, and the tee
command. For this script, suggestions were made for how the script could be modified. These are well worth pursuing to solidify and improve your new skills.
The chapter ended with a very fun and simple script for sending yourself a text message. We explored the curl
utility, along with SMS concepts. Although this is a fun script, it can be modified and used for more serious purposes.
Thanks for joining us on this journey through the Linux command line and shell scripting. We hope you've enjoyed the journey and have learned how to get around on the command line and how to create shell scripts to save time. But don't stop your command line education here. There's always something new being developed in the open source world, whether it's a new command line utility or a full-blown shell. Stay in touch with the Linux community and follow along with the new advances and features.