Bash example, Part 2: More Bash Basic Programming

xiaoxiao2021-03-06  88

Daniel Robbins President and CEO, Gentoo Technologies, Inc. April 2000

In the previous Bash introductory article, Daniel Robbins explains some basic elements of the scripting language and the use of Bash. In this article (ie, the second part), Daniel continues the previous content, and explains the basic structure of the condition (if-kil), cycle and more Bash.

Let's take a look at the simple skills of processing command lines, and then look at the BASH basic programming structure.

In an introductory article, we use the environment variable "$ 1" to reference the first command line from variables. Similarly, "$ 2", "$ 3" can be used to reference the second and third arguments passing 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 $ #

This except for the following two details. First, "$ 0" will expand the script name from the command line, "$ #" will extends to the number of auto-variables passing to the script. The above script is used to understand its working principle by transmitting different types of command lines.

Sometimes you need to reference all command lines from variables. For this purpose, Bash implements the variable "$ @", which extends into all command line parameters separated by spaces. In the "for" loop section later here, you will see an example of using this variable.

Bash Programming Structure If you have used process language such as C, Pascal, Python, or Perl, you must be familiar with the standard programming structure as the "IF" statement and "for" loop. Most of these standard structures, BASH has its own version. In the next few sections, several Bash structures will be introduced and the differences in structures in other programming languages ​​you are already familiar with. If there is not much programming before, don't worry. I have sufficient information and examples to keep you with the progress of this article.

Convenient Conditional Statement If you have written the code related to the file with C, you should know: To compare a specific file, you need a lot of work than another file. That is because c does not have any internal syntax to perform this comparison, two STAT () calls and two STAT structures must be used for manual comparison. In contrast, BASH has built-in standard file comparison operators, so determines if "/ tmp / myfile is read" is as easy as viewing "$ myvar is greater than 4".

The following table lists the most common BASH comparison operators. Also, how to use the example of each option correctly. Example To follow it after "if". E.g:

IF [-z "$ myvar"]

THEN

Echo "Myvar Is Not Defeed"

Fi

Operator Description Sample File Comparison Operator - E FileName If the FileName exists, true [-e / var / log / syslog] -d filename If FileName is a directory, true [-d / tmp / mydir] -f filename If FileName is a regular file, true [-f / usr / bin / grep] -l filename If filename is a symbolic link, true [-l / usr / bin / grep] -r filename can be read, then To true [-r / var / log / syslog] -w filename If FileName can be written, it is true [-w /var/mytmp.txt] -x filename if filename can be executed, it is true [-l / usr / BIN / grep] filename1 -nt filename2 If FileName1 is new than filename2, it is true [/ TMP / Install / etc / services -nt / etc / services] filename1 -ot filename2 If FileName1 is older than filename2, it is true [/ boot / BZIMAGE -OT ARCH / I386 / BOOT / BZIMAGE] String Compare Operator (please pay attention to the use of quotation marks, this is a good way to prevent space for disrupt code) -z String If the String length is zero, it is true [-z "$ Myvar "] -N String If the String length is not zero, it is true [-n" $ myvar "] string1 = string2 If string1 is the same as String2, it is true [" $ myvar "=" one two three "] string1! = String2 If string1 is different from String2, it is true ["$ myvar"! = "one two three"] arithmetic comparison operator Num1 -EQ Num2 equal to [3-EQ $ MyNum] Num1 -ne Num2 is not equal to [3 -ne $ MyNUM] Num1 -lt Num2 less than [3 -LT $ mynum] Num1 -le Num2 less than or equal to [3 -LE $ mynum] Num1 -Gt Num2 is greater than [3 -GT $ mynum] NUM1 -GE NUM2 is greater than or equal to [3 -GE $ MyNum] Sometimes, there are several different ways to perform specific comparisons. For example, the following two code segments are the same:

IF [$ myvar "-eq 3]

THEN

Echo "Myvar Equals 3"

Fi

IF [$ myvar "=" 3 "]

THEN

Echo "Myvar Equals 3"

Fi

The above two compare the same function, but the first use of the arithmetic comparison operator, and the second use of the character string compare operator.

String Comparison Note Most of the time, although you can not use a double quoted number of strings and string variables, this is not a good idea. why? Because if there is a space or tabtogram in the environment variable, Bash will not be able to distinguish it, so 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 the MyVar is equal to "foo", the code will work according to the expected, not printing. However, if MYVAR is equal to "Foo Bar Oni", the code will fail because of the following error: [: Too Many Arguments

In this case, "$ myvar" (equal to "Foo Bar Oni") is confused by Bash. After Bash extension "$ myvar", the code is as follows:

[foo bar oni = "foo bar oni"]

Because the environment variable is not placed in double quotes, Bash believes that there is too much variable in square brackets. This problem can be eliminated with double quotes. Remember, if you develop a habit of all string from variables from double quotes, you will remove a lot of similar programming errors. "foo bar oni" should be written:

IF ["$ myvar" = "foo bar oni"]

THEN

Echo "YES"

Fi

More Reference Details If you want to extend environment variables, you must use double quotes, rather than single quotes. Single quotes disable variables (and history) extensions.

The above code will work according to the expected, and there will be no unpleasant accidents.

Cycle structure: "for" is ok, the conditional statement has been tested, and the Bash loop structure is explored below. We will start from the standard "for" cycle. 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's happening? The "for x" section in the "for" loop defines a new environment variable named "$ x" (also known as loop control variable), and its value is set to "One", "Two", "Three "And" four ". After each assignment, the code between the cyclic body ("Do" and "DONE") is performed. In the circulation body, like other environment variables, use standard variable extension syntax to reference loop control variables "$ x". Also note that the "for" loop always receives some 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, even file wildcards. Take a look at the example below, this example demonstrates how to use 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 above code lists each file that starts with "R" in / ETC. To do this, BASH first gets wildcard / etc / r * before performing a loop, then expand it, with strings /etc/rc.d /etc/resolv.conf /etc/resolv.conf ~ / etc / rpc replace. Once the loop is entered, according to whether the "- D" condition operator is used to perform two different operations. If it is a directory, "(DIR)" is attached to the output line. You can also use multiple wildcards in the word list, or even environment variables:

For x in / etc / r ??? / var / lo * / home / DRobbins / mystuff / * / tmp / $ {mypath} / *

DO

CP $ x / mnt / mydir

DONE

Bash will perform wildcards and environment variable extensions at all correct locations and may create a very long word list.

Although all wildcard extensions use an absolute path, the relative path can also be used, as shown below:

For x in ../ * mystuff / *

DO

Echo $ x is a silly file

DONE

In the above example, Bash performs a wildcard extension relative to the current working directory, just like using a relative path in the command line. Study a wildcard expansion. You will notice that if the absolute path is used in a wildcard, Bash extends wildcard to a absolute path list. Otherwise, BASH will use a relative path in the list list. If only files in the current working directory (for example, if "for x in *") is entered, the resulting file list will have a prefix of the path information. Keep in mind that you can use the "BaseName" executable program to remove the previous path information as follows:

For x in / var / log / *

DO

Echo `Basename $ x` is a file limited in / var / log

DONE

Of course, it is often very convenient to perform cycles on the command line of the script. Here is an example of how to use the "$ @" variable mentioned in this article:

#! / usr / bin / env bash

For Thing in "$ @"

DO

Echo you type $ {thing}.

DONE

Output:

$ allargs hello there you silly

You typed hello.

You typed there.

You Typed you.

You typed silly.

Shell Math Before learning another type of loop structure, it is best to be familiar with how to perform shell arithmetic. Yes, this is true: You can use the shell structure to perform a simple integer operation. It is only necessary to use a specific arithmetic expression to "$ (" and "))", BASH can 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

You are already familiar with how to perform mathematical operations, now introduce other two Bash cyclic structures "while" and "unsil".

More cyclic structure: "while" and "unsil" as long as the specific condition is true, the "while" statement will execute, its format is as follows: While [Condition]

DO

Statements

DONE

Usually use the "while" statement to loop a certain number of times, for example, the following example will cycle 10 times:

myvar = 0

While [$ myvar -ne 10]

DO

Echo $ MyVar

MYVAR = $ (($ MYVAR 1))

DONE

It can be seen that the above example uses an arithmetic expression to make the condition finally false and cause the loop termination.

"Until" statement provides the opposite "while" statement: as long as the specific condition is false, they repeat. Below is a "Until" loop with the previous "While" cycle:

myvar = 0

Until [$ myvar-eq 10]

DO

Echo $ MyVar

MYVAR = $ (($ MYVAR 1))

DONE

The CASE statement CASE statement is another convenient conditional structure. Here has an example fragment:

Case "$ {x ## *.}" in

gz)

Gzunpack $ {SROOT} / $ {x}

;

BZ2)

BZ2UNPACK $ {SROOT} / $ {x}

;

*)

Echo "Archive Format Not Recognized."

exit

;

ESAC

In the above example, Bash first extends "$ {x ## *.}". In the code, "$ x" is the name of the file, "$ {x ##. *}" Removes all the text other than the text after the last period of the file. Then, Bash will compare the value listed on the left of the ")". In this example, "$ {x ##. *}" First compared with "GZ", then "BZ2", and finally "*". If "$ {x ##. *}" Matches any of these strings or modes, the row after ")" is performed until ";;", then Bash will continue to perform the endorse "eSAC". Row. If you do not match any modes or strings, no code rows are performed, in which a code block is to be executed, because any string that does not match "GZ" or "BZ2" will be "will" * "Mode match.

Functions and Namespaces in Bash, can even define a function similar to other procedure languages ​​such as Pascal and C). In Bash, the function can even receive the argument using the script to receive command lines or different variables. Let's take a look at the sample function, then 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 can use the "case" statement to write the above code. Do you know how to write?

We define a function called "tarview" above, which receives an argument, that is, some type of TAR file. When the function is executed, it determines which TAR file type (uncompressed, gzip compressed or bzip2 compressed), print a row information message, then display the contents of the TAR file. The above function should be called (after input, paste or find this function, call it from the script or command line):

$ 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 - r - ajr / abbot 1143 1997-09-04 04:06 Shorten-2.3A / Makefile

-rw-r - r - r - ajr / abbot 1199 1996-02-04 12:24 Shorten-2.3a / install

-rw-r - r - r - ajr / abbot 839 1996-05-29 00:19 Shorten-2.3a / license

....

Use them to interactively, don't forget, you can put the function (such as the function above) in ~ / .bashrc or ~ / .bash_profile to use them in Bash.

As you can see, you can use the same mechanism as the reference command lines to definition from internal references internally. In addition, the "$ #" macro will be expanded into the number of arguments. The only thing that may not be exactly the same is the variable "$ 0", which extends into string "Bash" (if you run from the shell interactive function) or call the function's script name.

Namespaces often need to create environment variables in the function. Although it is possible, there is still a technical detail to know. In most compiled languages ​​(such as c), the variable is placed in a separate local namespace when the variable is created inside the function. Therefore, if a function called MyFunction is defined in C, and in this function defines an argument called "X", any global variable called "X" is not subject to Its impression thus eliminates the negative effect.

This is this in C, but it is not in Bash. In Bash, you add it to the global namespace whenever you create an environment variable inside the function. This means that this variable will override the global variable other than the function and continue exit 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 you run this script, it will output "One Two Three Three", which shows how "$ myvar" defined in the function affects the global variable "$ myvar", and how loop control variable "$ x" will continue after the function exits Presented (if the "$ x" global variable is present, it will also be affected). In this simple example, it is easy to find the error and correct the error by using other variable names. But this is not the right way, the best way to solve this problem is to prevent the possibility of impact global variables by using the "local" command. When you create a variable in the function within a function, you will be placed in a local namespace and will not affect any global variables. Here is how to implement the above code so that the global variable is not rewritten:

#! / 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 will output "Hello" - do not rewrite the global variable "$ myvar", "$ x" does not continue to exist outside MyFunc. In the first line of the function, we created the local variable x to be used later, and in the second example (local myvar = "one two through"), we created a local variable MYVAR and assigned it to it. When the loop control variable is defined as a local variable, it is very convenient to use it because it is not allowed: "for local x in $ myvar". This function does not affect any global variable, encourage you to design all functions in this way "Local" should not be used when you want to modify global variables.

Conclusion We have learned the most basic Bash feature, now you have to look at how BASH develops the entire application. The next part is going to talk. Goodbye!

Reference

Read the introductory Bash article, "Bash instance, Part 1" on DeveloperWorks Visit the GNU's Bash Home View Bash Online Reference Manual

Transfer from: IBM DeveloperWorks China website

转载请注明原文地址:https://www.9cbs.com/read-125030.html

New Post(0)