The book "Linux Command Prompt. The complete guide. 2nd int. ed. "

image Hello, habrozhiteli! The international bestseller “Linux Command Line” will help you overcome the path from the first timid clicks on the keys to the confident creation of complete programs for the latest version of bash - the most popular Linux shell. The second edition talks about new features in bash 4.x, such as new redirection operators and wildcard operations. You will learn the timeless command line skills: navigating the file system, setting up the environment, chaining commands, and matching with regular expressions. You will comprehend the philosophy behind many command-line tools, understand the rich heritage of supercomputers from Unix, and learn about the knowledge accumulated by generations of gurus who have excluded the mouse from their arsenal of tools. Having overcome the first “shell shock”, you will understand how natural and logical this way of interacting with a computer is.



Excerpt. Chapter 25. Beginning of the project



In this chapter, we start creating the program. The goal of this project is to show how you can use the various capabilities of the shell to create programs and, most importantly, to create good programs.



Next we will write a report generator . It will display a variety of information about the system and its status in HTML format, so that it can be viewed in a web browser.



Typically, the creation of programs is carried out in several stages, at each of which new functions and capabilities are added. At the end of the first stage, our program will play a minimal HTML page without any information. We will add this information in the next steps.



Stage One: Minimum Document



First of all, let's determine what the format of a well-formed HTML document looks like. It has the following form:



<html> <head> <title> </title> </head> <body>  . </body> </html>
      
      





If you enter this text in a text editor and save it in a file called foo.html , we can open it by entering the following URL in Firefox: file: ///home/username/foo.html .

At the first stage, we will create a program that will output this HTML markup to standard output. Writing such a program is very simple. Open a text editor and create a file called ~ / bin / sys_info_page:



 [me@linuxbox ~]$ vim ~/bin/sys_info_page
      
      





And then enter the following program:



 #!/bin/bash #        echo "<html>" echo " <head>" echo " <title>Page Title</title>" echo " </head>" echo " <body>" echo " Page body." echo " </body>" echo "</html>"
      
      





Our first version contains a shebang line, a comment (welcome) and a sequence of echo commands, one for each line output. After saving the file, make it executable and try to run:



 [me@linuxbox ~]$ chmod 755 ~/bin/sys_info_page [me@linuxbox ~]$ sys_info_page
      
      





After starting, the text of the HTML document should appear on the screen, because the echo commands in the script send their lines to standard output. Run the program again and redirect the output to the sys_info_page.html file to see the result in a web browser:



 [me@linuxbox ~]$ sys_info_page > sys_info_page.html [me@linuxbox ~]$ firefox sys_info_page.html
      
      





So far, so good.



When developing programs, you should always remember about simplicity and clarity. Maintenance is easier when the program is easy to read and easy to understand, not to mention the fact that the program is easier to write when it is possible to reduce the amount of manual input. The current version of the program works great, but it can be simplified. Combining all echo commands into one will definitely make it easier in the future to add new lines to the program output. Therefore, we change the program as shown below:



 #!/bin/bash #        echo "<html> <head> <title>Page Title</title> </head> <body> Page body. </body> </HTML>"
      
      





Quoted strings can include line feeds and, accordingly, contain multiple lines of text. The shell will continue to read text until it encounters a closing quote. This rule also applies on the command line:



 [me@linuxbox ~]$ echo "<html> > <head> > <title>Page Title</title> > </head> > <body> > Page body. > </body> > </html>"
      
      





The> character at the beginning of each line is a prompt to enter a shell defined by its PS2 variable. It appears whenever a multi-line instruction is entered. This feature is still obscure, but then, when we get acquainted with multi-line program instructions, its advantages will become obvious.



Step Two: Add Some Data



Now that the program is able to generate a minimal document, add some data to the report. To do this, make the following changes:



 #!/bin/bash #        echo "<html> <head> <title>System Information Report</title> </head> <body> <h1>System Information Report</h1> </body> </html>"
      
      





Here is added the name of the page and the title in the body of the report.



Variables and Constants



There was a problem in our script. Have you noticed that the System Information Report line is repeated twice? In general, for such a tiny scenario this is not such a big problem, but imagine a really long scenario in which this line is repeated many times. If you need to change the name in such a scenario, you will have to make changes in many places, and this is a lot of manual work. Is it possible to change the script so that the string is defined in it only once? This would greatly simplify the maintenance of the script in the future. Yes, it is possible, for example, like this:



 #!/bin/bash #        title="System Information Report" echo "<html> <head> <title>$title</title> </head> <body> <h1>$title</h1> </body> </html>"
      
      





By creating a variable called title and assigning it the value System Information Report, we took advantage of parameter substitution and placed the string in many places.



But how to create a variable? Simple - just use it. When the shell encounters a variable, it automatically creates it. This differs from many programming languages ​​in which variables must be explicitly declared or defined before it is used. The command shell is too liberal in this regard, which ultimately leads to some problems. For example, consider the following script executed on the command line:



 [me@linuxbox ~]$ foo="yes" [me@linuxbox ~]$ echo $foo yes [me@linuxbox ~]$ echo $fool [me@linuxbox ~]$
      
      





We first assigned the value yes to the variable foo and then outputting its value with the echo command. Next, we tried again to display the value of the variable, but made a typo by specifying the name fool, and we got an empty string. This result is explained by the fact that the shell successfully created the fool variable upon encountering it and assigned it an empty default value. From this example it follows that you need to carefully monitor the spelling! It is also important to understand what actually happened in this example. From previous acquaintance with the features of the substitution mechanism, we know that the team



 [me@linuxbox ~]$ echo $foo
      
      





exposed to the mechanism of parameter substitution, resulting in the form



 [me@linuxbox ~]$ echo yes
      
      





On the other hand, the team



 [me@linuxbox ~]$ echo $fool
      
      





turns into



 [me@linuxbox ~]$ echo
      
      





Nothing is substituted for an empty variable! This can cause errors in commands that require arguments. For example:



 [me@linuxbox ~]$ foo=foo.txt [me@linuxbox ~]$ foo1=foo1.txt [me@linuxbox ~]$ cp $foo $fool cp:  'foo.txt'  ,      "cp --help"    .
      
      





We assigned values ​​to two variables, foo and foo1. And then they tried to execute the cp command, but made a typo in the name of the second argument. After processing by the lookup mechanism, the cp command received only one argument, although it requires two.



The following are a few rules for naming variables:





The name variable means a value that can change, and in many applications, variables are used that way. However, the title variable in our application is used as a constant . A constant, like a variable, has a name and contains a value. The only difference is that the value of the constant does not change. In an application that performs geometric calculations, you can define a PI constant with a value of 3.1415, instead of using this number throughout the program. The shell does not distinguish between constants and variables; These terms are used primarily for the convenience of the programmer. A typical convention is to use uppercase letters to indicate constants and lowercase letters for true variables. Let's change the scenario to bring it into line with this convention:



 #!/bin/bash #        TITLE="System Information Report For $HOSTNAME" echo "<html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> </body> </html>"
      
      





Along the way, we supplemented the name by adding the value of the HOSTNAME shell variable to the end. This is the network name of the machine.

NOTE



In fact, the shell has a mechanism to guarantee the immutability of constants, in the form of a built-in declare command with the -r parameter (read-only - read-only). If you assign a value to the TITLE variable as shown below:



 declare -r TITLE="Page Title"
      
      





the shell will not allow the value to be re-assigned to the TITLE variable. This mechanism is rarely used in practice, but it is available and can be used in particularly stringent scenarios.


Assigning Values ​​to Variables and Constants



We have come to the moment when our knowledge of the features of the operation of the substitution mechanism begins to bear fruit. As we have seen, assigning values ​​to variables is done like this:



 =
      
      





where variable is the name of the variable and value is the string. Unlike some other programming languages, the shell does not care about the types of values ​​assigned to variables; she interprets all values ​​as strings. It is possible to force the shell to limit the range of assigned values ​​to integers by using the declare command with the -i option, but like declaring read-only variables, this feature is rarely used in practice.



Note that there are no spaces in the assignment operator between the variable name, the equal sign, and the value. And what can the meaning consist of? From anything you can expand into a string.



 a=z #   a  "z". b="a string" #      . c="a string and $b" #     , # ,   . d=$(ls -l foo.txt) #   . e=$((5 * 7)) #    . f="\t\ta string\n" #  ,   #     .
      
      





In one line, you can assign several variables at once:



 a=5 b="a string"
      
      





When using substitution, variable names can be enclosed in optional curly braces {}. This is useful when the variable name becomes ambiguous in the surrounding context. The following example attempts to rename myfile to myfile1 using a variable:



 [me@linuxbox ~]$ filename="myfile" [me@linuxbox ~]$ touch $filename [me@linuxbox ~]$ mv $filename $filename1 mv:  'myfile'  ,      "mv --help"    .
      
      





This attempt was unsuccessful because the shell interpreted the second argument of the mv command as the name of a new (and empty) variable. The following shows how to solve this problem:



 [me@linuxbox ~]$ mv $filename ${filename}1
      
      





By adding curly braces, we ensured that the shell would not interpret the last character 1 as part of the variable name.



Note



When performing substitution, it is recommended that the variable names and commands be enclosed in double quotation marks to prevent the shell from breaking lines into words. It is especially important to use quotation marks when a variable may contain a file name.
We will use this opportunity to add additional data to the report, namely the date and time of the report, as well as the name of the user who created the report:



 #!/bin/bash #        TITLE="System Information Report For $HOSTNAME" CURRENT_TIME=$(date +"%x %r %Z") TIME_STAMP="Generated $CURRENT_TIME, by $USER" echo "<html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> </body> </html>"
      
      





Embedded Documents



We looked at two different text output methods, and both use the echo command. However, there is another, third method, called an inline document (here document), or an inline script (here script). An embedded document is an additional form of I / O redirection that passes text embedded in a script to standard command input. This redirection works like this:



  <<   
      
      





where the command is the name of the command that receives the specified text through standard input, and the indicator is the line marking the end of the embedded text. We’ll modify the scenario using the embedded document in it:



 #!/bin/bash #        TITLE="System Information Report For $HOSTNAME" CURRENT_TIME=$(date +"%x %r %Z") TIME_STAMP="Generated $CURRENT_TIME, by $USER" cat << _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> </body> </html> _EOF_
      
      





Now, instead of the echo command, the script uses the cat command and the embedded document. The line _EOF_ was chosen for the indicator role (means end-of-file - end of file , common agreement), and it marks the end of the embedded text. Please note that the indicator line should be in a separate line, one, and no spaces should follow it.



But what are the benefits of using the embedded document here? Virtually none, except that the quotation marks inside embedded documents lose their special meaning for the shell. The following is an example of using an embedded document on the command line:



 [me@linuxbox ~]$ foo="some text" [me@linuxbox ~]$ cat << _EOF_ > $foo > "$foo" > '$foo' > \$foo > _EOF_ some text "some text" 'some text' $foo
      
      





As you can see, the shell does not pay any attention to quotes. She interprets them as ordinary characters. Thanks to this, we freely insert quotation marks into embedded documents. This circumstance can be used when developing reporting programs.



Embedded documents can be used with any commands that accept data from standard input. The following example uses a built-in document to send a sequence of commands to the ftp program to download a file from a remote FTP server:



 #!/bin/bash #     FTP FTP_SERVER=ftp.nl.debian.org FTP_PATH=/debian/dists/stretch/main/installer-amd64/current/images/cdrom REMOTE_FILE=debian-cd_info.tar.gz ftp -n << _EOF_ open $FTP_SERVER user anonymous me@linuxbox cd $FTP_PATH hash get $REMOTE_FILE bye _EOF_ ls -l $REMOTE_FILE
      
      





If you replace the redirect operator << with << -, the command shell will ignore the initial tab characters in the embedded document. Due to this, indents can be added to the embedded document for greater readability:



 #!/bin/bash #     FTP FTP_SERVER=ftp.nl.debian.org FTP_PATH=/debian/dists/stretch/main/installer-amd64/current/images/cdrom REMOTE_FILE=debian-cd_info.tar.gz ftp -n <<- _EOF_ open $FTP_SERVER user anonymous me@linuxbox cd $FTP_PATH hash get $REMOTE_FILE bye _EOF_ ls -l $REMOTE_FILE
      
      





However, using this feature is not always convenient, because for the indentation many text editors (and programmers themselves) prefer to use space characters instead of tabs.



Conclusion



In this chapter, we started developing a project with which we will go through all the stages of creating a script. We got acquainted with variables and constants and the features of their use. They are more often than other software components used for substitution. We also saw how to organize the output of information in a script, and got acquainted with different methods of embedding blocks of text.



about the author



William Shotts is a professional software developer with more than 30 years of experience who has been actively using the Linux operating system for more than 20 years. He has rich experience in software development, technical support, quality control and writing documentation. He is also the creator of LinuxCommand.org, an educational and educational site dedicated to Linux, where news, reviews, and Linux command line support are provided.



About Science Editor



Jordi Gutiérrez Hermoso is a programmer, mathematician, and ethical hacker. Since 2002, it exclusively uses Debian GNU / Linux, not only at home, but also at work. Jordi is involved in the development of GNU Octave, a free computing environment that is largely compatible with Matlab, as well as Mercurial, a distributed version control system. He is fond of pure and applied mathematics, ice skating, swimming and knitting. Recently, he thinks a lot about the problems of greenhouse gas emissions and participates in actions to save rhinos.



»More details on the book can be found on the publisher’s website

» Contents

» Excerpt



25% off coupon for hawkers - Linux



Upon payment of the paper version of the book, an electronic book is sent by e-mail.



All Articles