Bash instance, part 1

Source: Internet
Author: User
Tags echo name

Let's take a look at the simple technique for processing command line independent variables, and then look at the basic programming structure of bash.

Receive independent variable

In the sample program in the introductory article, we use the environment variable "$1" to reference the first command line independent variable. Similarly, you can use "$2" and "$3" to reference the second and third independent variables passed to the script. Here is an example:

 #!/usr/bin/env bash  echo name of script is $0 echo first argument is $1 echo second argument is $2 echo seventeenth argument is $17 echo number of arguments is $#

In addition to the following two details, this example is not required. First, "$0" is extended to the script name called from the command line, and "$ #" is extended to the number of independent variables passed to the script. Test the above script and learn how it works by passing different types of command line independent variables.

Sometimes a single reference is requiredAllCommand Line independent variable. For this purpose, bash implements the variable "$ @", which is extended to all command line parameters separated by spaces. In the "for" loop later in this article, you will see an example of using this variable.

Back to Top

Bash programming structure

If you have used programming in a procedural language like C, Pascal, Python, or Perl, you must be familiar with the standard programming structure like the "if" Statement and "for" loop. Bash has its own version for most of these standard structures. In the following sections, we will introduce several bash structures and demonstrate the differences between these structures and those in other programming languages that you are already familiar. Don't worry if you haven't programmed much before. I provide enough information and examples to keep up with the progress of this article.

Back to Top

Convenient condition statements

If you have used C to Write File-related code, you should know: To compare a specific file, whether it is more work than another file. That's because C does not have any built-in syntax for this comparison. Two Stat () calls and two stat structures must be used for manual comparison. Instead, Bash has built-in standard file comparison operators. Therefore, it is as easy to determine whether "/tmp/myfile is readable" as to check whether "$ myvar is greater than 4.

The following table lists the most common bash comparison operators. Examples of how to correctly use each option are also provided. The example must be followed by "if. For example:

 if [ -z "$myvar" ]then     echo "myvar is not defined"fi

Operator Description Example
File comparison operator
-EFilename IfFilenameYes, true [-E/var/log/syslog]
-DFilename IfFilenameIs a directory, it is true [-D/tmp/mydir]
-FFilename IfFilenameIs a regular file, it is true [-F/usr/bin/grep]
-LFilename IfFilenameIs a symbolic link, it is true [-L/usr/bin/grep]
-RFilename IfFilenameReadable, true [-R/var/log/syslog]
-WFilename IfFilenameWritable, true [-W/var/mytmp.txt]
-XFilename IfFilenameExecutable, true [-L/usr/bin/grep]
Filename1-NTFilename2 IfFilename1RatioFilename2New, true [/Tmp/install/etc/services-nt/etc/services]
Filename1-OtFilename2 IfFilename1RatioFilename2Old, true [/Boot/bzimage-ot ARCH/i386/boot/bzimage]
String comparison operator(Please pay attention to the use of quotation marks. This is a good way to prevent space from disturbing the code)
-ZString IfStringIf the length is zero, it is true. [-Z "$ myvar"]
-NString IfStringNon-zero length, true [-N "$ myvar"]
String1=String2 IfString1AndString2Same, true ["$ Myvar" = "One Two Three"]
String1! =String2 IfString1AndString2Otherwise, true ["$ Myvar "! = "One Two Three"]
Arithmetic comparison operator
Num1-EQNum2 Equal [3-EQ $ mynum]
Num1-NeNum2 Not equal [3-ne $ mynum]
Num1-LtNum2 Less [3-lt $ mynum]
Num1-LeNum2 Less than or equal [3-Le $ mynum]
Num1-GTNum2 Greater [3-GT $ mynum]
Num1-GeNum2 Greater than or equal [3-ge $ mynum]

Sometimes there are several different methods for specific comparison. For example, the following two code segments have the same functions:

 if [ "$myvar" -eq 3 ]then      echo "myvar equals 3"fi   if [ "$myvar" = "3" ]then      echo "myvar equals 3"fi

The above two comparisons perform the same function, but the first uses arithmetic comparison operators, and the second uses string comparison operators.

Back to Top

String comparison

Most of the time, although double quotation marks that enclose strings and string variables are not used, this is not a good idea. Why? If the environment variable happens to have a space or tabulation key, Bash will not be able to distinguish and thus it will not work properly. Here is an error comparison example:

 if [ $myvar = "foo bar oni" ]then      echo "yes"fi

In the above example, if myvar is equal to "foo", the code will work as expected without printing. However, if myvar is equal to "foo bar ONI", the Code fails due to the following error:

 [: too many arguments

In this case, the spaces in "$ myvar" (equal to "foo bar ONI") confuse bash. After bash expands "$ myvar", the Code is as follows:

 [ foo bar oni = "foo bar oni" ]

Bash considers that there are too many independent variables in square brackets because the environment variables are not placed in double quotes. Double quotation marks can be used to enclose string independent variables to eliminate this problem. Keep in mind that many similar programming errors will be removed if all string independent variables are enclosed in double quotation marks. Comparison of "foo bar ONI"ShouldWritten:

 if [ "$myvar" = "foo bar oni" ]then      echo "yes"fi

More references

To expand environment variables, you must useDouble quotation marksInstead of being enclosed in single quotes. Single quotesDisableVariable (and history) extension.

The above code will work as expected without any unpleasant surprises.

Back to Top

Loop Structure: ""

Well, we have already talked about conditional statements. Next we should explore the bash loop structure. We will start with the standard "for" loop. Here is a simple example:

#! /Usr/bin/ENV bash for X in one two three four do echo number $ X done output: Number one number two number three number four

What happened? The "for X" section in the "for" loop defines a new environment variable named "$ X" (also called a loop control variable ), its values are set to "one", "two", "three", and "four" in sequence ". After each assignment, run the code between "do" and "done ). In a loop, like other environment variables, use the standard variable extension syntax to reference the loop control variable "$ X ". Note that the "for" loop always receives a certain type of word list after the "in" statement. In this example, four English words are specified, but the word list can also reference files on the disk, or even file wildcards. Take a look at the following example to demonstrate how to use the standard shell wildcard:

#! /Usr/bin/ENV bash for myfile in/etc/R * do if [-d "$ myfile"] Then ECHO "$ myfile (DIR) "Else echo" $ myfile "fi done output:/etc/rc. D (DIR)/etc/resolv. conf/etc/resolv. conf ~ /Etc/RPC

The code above lists each file starting with "R" in/etc. To do this, bash first obtains the wildcard/etc/R * Before executing the loop, then extends it, and uses the string/etc/rc. d/etc/resolv. conf/etc/resolv. conf ~ /Etc/RPC replacement. Once a loop is entered, the "-d" condition operator is used to perform two different operations based on whether the myfile is a directory. If it is a directory, "(DIR)" is appended to the output line.

You can also use multiple wildcards or even environment variables in the word list:

  for x in /etc/r--? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/* do     cp $x /mnt/mydir done

Bash will execute wildcards and environment variable extensions in all correct locations, and may create a very long word list.

Although all wildcard extension examples UseAbsolutePath, but you can also use the relative path, as shown below:

  for x in ../* mystuff/* do     echo $x is a silly file done

In the above example, bash executes wildcard extension relative to the current working directory, just like using relative paths in the command line. Study wildcard extension. You will notice that if an absolute path is used in the wildcard, bash expands the wildcard into an absolute path list. Otherwise, bash uses the relative path in the word list. If you only reference files in the current working directory (for example, if you enter "for X in *"), the generated file list will have no prefix for path information. Remember, you can use the "basename" executable program to remove the preceding path information, as shown below:

  for x in /var/log/* do     echo `basename $x` is a file living in /var/log done

Of course, it is usually convenient to execute a loop on the command line independent variables of the script. Here is an example of how to use the variable "$ @" mentioned at the beginning of this article:

#! /Usr/bin/ENV bash for thing in "$ @" Do echo you typed $ {thing }. done output: $ allargs hello there you silly you typed hello. you typed there. you typed you. you typed silly.

Back to Top

Shell Arithmetic

Before learning another type of loop structure, you 'd better familiarize yourself with how to execute shell arithmetic. Yes, indeed: You can use the shell structure to perform simple integer operations. Bash only needs to enclose a specific arithmetic expression with "$ (" and ")" to calculate the expression. Here are some examples:

 $ echo $(( 100 / 3 )) 33 $ myvar="56" $ echo $(( $myvar + 12 )) 68 $ echo $(( $myvar - $myvar ))0 $ myvar=$(( $myvar + 1 ))$ echo $myvar 57

Back to Top

More loop structures: "while" and ""

If the specified condition is true, the "while" statement is executed in the following format:

 while [ condition ] do     statements done

The "while" statement is usually used to loop for a certain number of times. For example, the following example loops 10 times:

 myvar=0 while [ $myvar -ne 10 ] do     echo $myvar     myvar=$(( $myvar + 1 )) done

We can see that in the above example, the arithmetic expression is used to make the condition finally false and cause the loop to terminate.

The "until" statement provides the opposite functionality of the "while" Statement: as long as the specific condition isFalse. The following is an "until" loop with the same function as the previous "while" loop:

 myvar=0 until [ $myvar -eq 10 ] do     echo $myvar     myvar=$(( $myvar + 1 )) done

Back to Top

Case statement

The case statement is another convenient condition structure. Here is an example snippet:

  case "${x##*.}" in      gz)            gzunpack ${SROOT}/${x}            ;;      bz2)            bz2unpack ${SROOT}/${x}            ;;      *)            echo "Archive format not recognized."            exit            ;; esac                                      

In the preceding example, bash first expands "$ {X ##*.}". In the Code, "$ X" is the name of the file. "$ {X #. *}" removes all texts except the last periods and texts in the file. Bash then compares the generated string with the value listed on the left. In this example, "$ {X #. *}" is compared with "GZ" first, then "bz2", and finally "*". If "$ {X ##. *} "if it matches any of these strings or modes, the line following") "is executed, bash then continues executing the line after the end character "esac. If no pattern or string is matched, no code line is executed. In this special code segment, at least one code block must be executed, because any string that does not match "GZ" or "bz2" will match the "*" pattern.

Back to Top

Functions and namespaces

In Bash, you can even define functions similar to other procedural languages (such as Pascal and C. In bash, functions can even receive arguments in a way similar to the command line arguments received by scripts. Let's take a look at the sample function definition and continue from there:

  tarview() {     echo -n "Displaying contents of $1 "     if [ ${1##*.} = tar ]then          echo "(uncompressed tar)"         tar tvf $1     elif [ ${1##*.} = gz ]then          echo "(gzip-compressed tar)"         tar tzvf $1     elif [ ${1##*.} = bz2 ]then          echo "(bzip2-compressed tar)"         cat $1 | bzip2 -d | tar tvf -fi }

Another situation

You can use the "case" statement to write the above Code. Do you know how to write it?

We defined a function named "tarview" above, which receives an independent variable, that is, a certain type of tar file. When executing this function, it determines the tar file type of the independent variable (uncompressed, Gzip compressed, or Bzip2 compressed), prints an information message, and then displays the content of the TAR file. You should call the above function as follows (call it from a script or command line after you input, paste, or find the function ):

 $ tarview shorten.tar.gz Displaying contents of shorten.tar.gz (gzip-compressed tar) drwxr-xr-x ajr/abbot         0 1999-02-27 16:17 shorten-2.3a/ -rw-r--r-- ajr/abbot      1143 1997-09-04 04:06 shorten-2.3a/Makefile -rw-r--r-- ajr/abbot      1199 1996-02-04 12:24 shorten-2.3a/INSTALL -rw-r--r-- ajr/abbot       839 1996-05-29 00:19 shorten-2.3a/LICENSE ....  

Use them interactively

Do not forget to place the function (the above function) IN ~ /. Bashrc or ~ /. Bash_profile to use them in bash at any time.

As you can see, you can use the same mechanism as referencing the command line independent variable to reference the independent variable within the function definition. In addition, the macro "$ #" is expanded to include the number of independent variables. The only variable that may not be exactly the same is "$0", which will be extended to the string "bash" (if the function is run interactively from the shell) or the name of the script that calls the function.

Back to Top

Namespace

You often need to create environment variables in functions. Although possible, there is still a technical detail to understand. In most compilation languages (such as C), when a variable is created inside a function, the variable is placed in a separate local namespace. Therefore, if you define a function named myfunction in C and define an independent variable named "X" in the function, then, any global variable named "X" (a variable other than a function) will not be impressed by it, thus eliminating negative effects.

This is true in C, but not in bash. In bash, every time an environment variable is created inside a function, it is addedGlobalNamespace. This means that this variable will overwrite the global variables outside the function and continue to exist after the function exits:

 #!/usr/bin/env bash  myvar="hello"  myfunc() {      myvar="one two three"     for x in $myvar     do         echo $x     done }  myfunc  echo $myvar $x

When running this script, it will output "One Two Three three", which shows how "$ myvar" affects global variables "$ myvar" defined in the function ", and how the cyclic control variable "$ X" continues to exist after the function exits (if the global variable "$ X" exists, it will also be affected ).

In this simple example, it is easy to locate the error and correct it by using other variable names. But this is not the correct method. The best way to solve this problem is to use the "local" command to prevent the possibility of affecting global variables from the beginning. When "local" is used to create variables in the functionLocalAnd does not affect any global variables. Here we demonstrate how to implement the above Code so that global variables are not overwritten:

  #!/usr/bin/env bash  myvar="hello"  myfunc() {     local x     local myvar="one two three"     for x in $myvar     do         echo $x     done }  myfunc  echo $myvar $x

This function outputs "hello" -- does not override the global variable "$ myvar", and "$ X" does not exist outside of myfunc. In the first line of the function, we create the local variable X to be used later. In the second example (local myvar = "One Two Three, we created the local variable myvar,At the same timeAssign a value to it. When defining a cyclic control variable as a local variable, it is easy to use the first form, because it cannot be said: "For local X in $ myvar ". This function does not affect any global variables. We encourage you to design some functions in this way. Only when you explicitly want to modify global variablesNoUse "local ".

Back to Top

Conclusion

We have learned the most basic bash function. Now we need to look at how to develop the entire application based on Bash. The next part is about to be discussed. Goodbye!

References

  • For more information, see the original article on the developerworks global site.

  • Read the introductory bash article,Developerworks"Bash instance, Part 1"
  • Visit the GNU's bash Homepage
  • View bash online reference manual

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.