Daniel Robbins
President and CEO, Gentoo Technologies, Inc.
March 2000
By learning how to program using the bash scripting language, you can make the daily interaction of Linux more interesting and productive. You can also use the familiar and favorite standard UNIX concepts (such as pipelines and redirection ). In this three-part series, Daniel Robbins provides an example of how to program using bash. He will describe very basic knowledge (which makes this series very suitable for beginners) and introduce more advanced features in subsequent series.
You may ask: Why do you want to learn bash programming? Well, here are some compelling reasons:
It is already running
You may find that you are currently running bash. Bash is a standard Linux Shell and is used for various purposes. Therefore, even if the default shell is changed, bash mayStillRun somewhere in the system. Because Bash is already running, any bash scripts that run in the future are naturally effective in using the memory because they share the memory with any running bash process. If the running tool is competent and well-performed, why should we load a 500 k interpreter?
It is already in use
Not only is Bash running, but you are still dealing with Bash every day. It is always there, so it makes sense to learn how to use it to the maximum extent. This will make your Bash experience more interesting and productive. But why learning Bash?Programming? It's easy because you are already thinking about how to run commands, cping files, and pipeline and redirection output. Why don't you learn a language to use and use the powerful and time-saving concepts that you are already familiar with and love? The command shell opens the potential of Unix systems, while Bash isThisLinux Shell. It is a high-level bond between you and your machine. Increase bash knowledge, which will automatically increase your productivity in Linux and Unix-that's simple.
Bash confusions
Learning bash in the wrong way is confusing. Many new users enter "Man Bash" to view the bash help page, but only get a very simple and technical shell functional description. Someone else enters "info Bash" (to view the GNU information document) and can only get a Help page that is re-displayed, or (if Lucky) a slightly friendly information document.
Although this may disappoint beginners, the standard bash document cannot meet everyone's requirements. It is only suitable for those who are already familiar with shell programming. The Help page does contain a lot of excellent technical information, but it does not help beginners.
This is the purpose of this series. In this series, I will show you how to actually use Bash programming concepts to write your own scripts. Different from the technical description, I will explain it in a simple language so that you not only know what to do, but also when to use it. At the end of the three series, you will be able to write complex bash scripts on your own, use Bash freely, and supplement your knowledge by reading (and understanding) Standard bash documents. Let's get started.
Environment Variable
In bash and almost all other shells, you can define environment variables, which are stored in ASCII strings. Environment variables are the most convenient: they are the standard part of the UNIX process model. This means that environment variables are not only used exclusively by shell scripts, but can also be used by compiled standard programs. When "exporting" environment variables in bash, any program running in the future can read the settings, whether it is a shell script or not. A good example is the vipw command, which usually allows the root user to edit the system password file. By setting the editor environment variable to the name of your favorite text editor, you can configure vipw to use this editor without using vi. If you are used to xemacs but do not like VI, this is very convenient.
The standard method for defining environment variables in Bash is:
$ myvar='This is my environment variable!' |
The preceding command defines an environment variable named "myvar" and contains the string "this is my environment variable! ". Note: first, there is no space on both sides of the equal sign "=". Any space will lead to an error (Please try it ). The second thing to note is: Although quotation marks can be omitted when defining a word, when the defined environment variable value is more than one word (including space or tabulation Key ), quotation marks are required.
Reference details For more information about how to use quotation marks in bash, see the reference section on the bash help page. The special character sequence is expanded (replaced) by other values to make string processing complicated in bash. This series only describes the most common reference functions. |
Third, although double quotation marks can usually be used to replace single quotation marks, in the above example, this will cause errors. Why? Because the bash feature called extension is disabled with single quotes, special characters and character series are replaced by values. For example ,"! "Is a history extension character. bash usually replaces it with the previous command. (Historical extensions are not described in this series, as they are not commonly used in bash programming. For more information about historical extensions, see the "historical extensions" section on the bash help page .) Although this macro-like function is very convenient, we only want to add a simple exclamation point after the environment variable, rather than a macro.
Now, let's take a look at how to actually use environment variables. Here is an example:
$ echo $myvarThis is my environment variable! |
By adding $ to the front of the environment variable, bash can replace it with the value of myvar. This is called variable extension in bash ". However, what will happen in this way:
We want to echo "fooThis is my environment variable! Bar ", but not like this. Where is the error? Simply put, the bash variable extension facility is in confusion. It cannot identify which variable to expand: $ m, $ my, $ myvar, $ myvarbar, and so on. How can we clearly tell which variable bash references? Try this:
$ echo foo${myvar}barfooThis is my environment variable!bar |
As you can see, when the environment variable is not clearly separated from the surrounding text, you can enclose it with curly brackets. Although $ myvar can be input faster and work correctly in most cases, $ {myvar} can be correctly analyzed through syntax in almost all cases. In addition, the two are the same, and the two forms of variable extension will be seen in the rest of this series. Remember: when the environment variables are not separated from the surrounding text by spaces (or tabulation keys), use a more explicit curly brackets.
In retrospect, we also mentioned the possibility of "exporting" variables. When an environment variable is exported, it can be automatically used by any script or executable program environment that will run in the future. Shell scripts can use the built-in environment variables of shell to support "Arrival" environment variables, while C Programs can use the getenv () function to call. Here are some examples of C code, input and compile them -- it will help us understand the environment variables from the perspective of C:
Myvar. c -- Sample environment variable C program
#include
#include
int main(void) { char *myenvvar=getenv("EDITOR"); printf("The editor environment variable is set to %s/n",myenvvar);}
|
Save the above Code to the file myenv. c, and then issue the following command for compilation:
Now there will be an executable program in the directory, which will print the editor environment variable value at runtime (if there is a value ). This is the case when running on my machine:
$ ./myenvThe editor environment variable is set to (null) |
Ah... because the editor environment variable is not set to any value, C program gets an empty string. Let's try to set it to a specific value:
$ EDITOR=xemacs$ ./myenvThe editor environment variable is set to (null) |
Although you want myenv to print the value "xemacs", it does not work very well because the environment variable has not been exported. This time let it work correctly:
$ export EDITOR$ ./myenvThe editor environment variable is set to xemacs |
Now, as you can see with your own eyes: if you do not export environment variables, the other process (in this example, the sample C program) will not see the environment variables. By the way, if you want to, you can define and export the environment variables in one line, as shown below:
This is the same as the two-line version. Now we will demonstrate how to use unset to remove environment variables:
$ unset EDITOR$ ./myenvThe editor environment variable is set to (null) |
Dirname and basename Note: dirname and basename are not files or directories on the disk. They are only string operation commands. |
Truncation string Overview
Truncates an initial string to a smaller independent block. It is one of the daily tasks executed by a shell script. Most of the time, shell scripts need to use a fully qualified path and find the final file or directory. Although it can be implemented using bash encoding (and interesting), the standard basename UNIX executable program can do this well:
$ basename /usr/local/share/doc/foo/foo.txtfoo.txt$ basename /usr/home/drobbinsdrobbins |
Basename is an easy tool for truncating strings. Its Related command dirname returns another part of the path discarded by basename.
$ dirname /usr/local/share/doc/foo/foo.txt/usr/local/share/doc/foo$ dirname /usr/home/drobbins//usr/home |
Command replacement
You need to know a simple operation: how to create an environment variable that contains executable command results. This is easy:
$ MYDIR=`dirname /usr/local/share/doc/foo/foo.txt`$ echo $MYDIR/usr/local/share/doc/foo |
The above is called "command replacement ". In this example, we need to point out several points. In the first lineReverse quotation marks. It is not a standard single quotation mark, but a single quotation mark usually located above the tab key on the keyboard. You can use the bash alternative command to replace the syntax to do the same thing:
$ MYDIR=$(dirname /usr/local/share/doc/foo/foo.txt)$ echo $MYDIR/usr/local/share/doc/foo |
As you can see, bash provides multiple methods to perform exactly the same operation. With command replacement, you can place any command or command pipeline between ''or $ () and assign it to environment variables. Really convenient! The following is an example to demonstrate how to use pipelines in command replacement:
MYFILES=$(ls /etc | grep pa)bash-2.03$ echo $MYFILESpam.d passwd |
Truncates a string like a professional
Although basename and dirname are good tools, you may sometimes need to perform more advanced string "truncation", not just standard path name operations. You can use the built-in variable extension function of bash to make it more convincing. Variable extensions of the standard type similar to $ {MYVAR} have been used. However, bash itself can also execute some convenient string truncation. Take a look at these examples:
$ MYVAR=foodforthought.jpg$ echo ${MYVAR##*fo}rthought.jpg$ echo ${MYVAR#*fo}odforthought.jpg |
In the first example, enter $ {MYVAR # * fo }. What exactly does it mean? Basically, enter the environment variable name in $ {}, two ##, followed by a wildcard ("* fo "). Bash then obtains MYVAR and finds the path starting from the string "foodforthought.jpg" and matching the wildcard "* fo ".LongestSubstring, and then intercept it from the beginning of the string. It may be difficult to understand at the beginning. To feel how this special "#" option works, let's take a step-by-step look at how bash completes this extension. First, it searches for the Child string that matches the "* fo" wildcard at the beginning of "foodforthought.jpg. The following are the detected substrings:
f fo MATCHES *fofoo foodfoodf foodfo MATCHES *fofoodforfoodfort foodforthfoodfortho foodforthoufoodforthougfoodforthoughtfoodforthought.jfoodforthought.jpfoodforthought.jpg |
After searching for matched strings, we can see that bash finds two matching strings. It selects the longest match, removes it from the beginning of the initial string, and returns the result.
The extension form of the second variable shown above looks the same as that of the first variable, but it only uses one "#" -- and bash executesAlmostThe same process. It looks at the same sub-string series as the first example, but bash removesShortestAnd then return the result. As soon as the sub-string "fo" is found, it removes "fo" from the string and returns "odforthought.jpg ".
This may be confusing. Remember this function in a simple way. When you search for the longest match, use # (because # ratio # Is long ). Use # when searching for the shortest match #. Look, it's not hard to remember! Wait, how do you remember to use the '#' character to remove it from the start of the string? Very easy! Note: On the U.S. keyboard, shift-4 is "$", which is an extension of the bash variable. On the keyboard, close to "$" on the left is "#". In this way, we can see that "#" is at the "Start" of "$", so (according to our memory), "#" removes characters from the start of a string. You may want to ask: how to remove characters from the end of a string. If we guess we use an American keyboard, close to "$"Right side("%), Then you can guess it. Here are some simple examples to explain how to cut the end of a string:
$ MYFOO="chickensoup.tar.gz"$ echo ${MYFOO%%.*}chickensoup$ echo ${MYFOO%.*}chickensoup.tar |
As you can see, except for removing the matching wildcard from the end of the string, the % and % variable extension options work the same way as the # And # variables. Note: If you want to remove the special character string from the end, you do not need to use the "*" character:
MYFOOD="chickensoup"$ echo ${MYFOOD%%soup}chicken |
In this example, "%" or "%" is not important because only one matching exists. Remember: if you forget to use "#" or "%", take a look at the 3, 4, and 5 keys on the keyboard and guess them.
You can use another form of variable extension to select a special character string based on the specific character offset and length. Enter the following lines in Bash:
$ EXCLAIM=cowabunga$ echo ${EXCLAIM:0:3}cow$ echo ${EXCLAIM:3:7}abunga |
String Truncation in this form is very simple. You only need to use a colon to separate the start character and the length of the substring.
Apply string Truncation
Now we have learned all about string truncation. Below is a simple and short shell script. Our script will accept a file as the independent variable, and then print: whether the file is a tar file. To determine whether it is a tar file, the search mode ". tar" will be found at the end of the file ". As follows:
Mytar. Sh -- a simple script
#!/bin/bashif [ "${1##*.}" = "tar" ]then echo This appears to be a tarball.else echo At first glance, this does not appear to be a tarball.fi |
Run this script, input it to the mytar. Sh file, and enter "chmod 755 mytar. Sh" to generate an executable file. Then, perform the tar file experiment as follows:
$ ./mytar.sh thisfile.tarThis appears to be a tarball.$ ./mytar.sh thatfile.gzAt first glance, this does not appear to be a tarball. |
Yes, it runs successfully, but it is not practical. Before making it more practical, let's take a look at the "if" statement used above. A boolean expression is used in the statement. In bash, the "=" comparison operator checks whether the strings are equal. In bash, all boolean expressions are enclosed in square brackets. But what is a Boolean expression actually testing? Let's take a look at the left side. Based on the string truncation knowledge learned above, "$ {1 ##*.} "Remove the longest part starting from the string contained in environment variable" 1 "*. "Match and return results. This will return all parts after the last "." In the file. Obviously, if the object ends with ". tar", the result is "tar" and the condition is true.
You may wonder what the "1" environment variable at the beginning is. Very simple -- $1 is the first command line independent variable passed to the script, $2 is the second, and so on. Well, we have reviewed the functions. Next we will look at the "if" statement.
If statement
Like most languages, bash has its own conditional form. The preceding format must be used. That is, place "if" and "then" in different rows, and align the "fi" required for "else" and the end with them horizontally. This makes the code easy to read and debug. In addition to the "if, else" format, there are other forms of "if" statements:
if [ condition ]then actionfi |
Only whencondition
If the statement is true, the operation is executed. Otherwise, no operation is executed and any row after "fi" is executed continues.
if [ condition ]then actionelif [ condition2 ]then action2...elif [ condition3 ]then else actionxfi |
In the above "elif" form, each condition is continuously tested and the first condition is met.TrueCondition. If no condition is true, the "else" operation is executed. if one condition is true, the row following the entire "if, elif, else" statement is continued.
Next time
We have learned the most basic bash functions. Now we need to speed up the process and prepare some practical scripts. In the next article, we will introduce loop concepts, functions, namespaces, and other important topics. Then, you will be ready to write more complex scripts. The third part focuses on some very complex scripts and functions, as well as several bash script design options. Goodbye!
References
- Visit the GNU's bash Homepage
- View bash online reference manual
Transferred from:IBM developerworks Chinese website