博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Bash 脚本基本语法
阅读量:2342 次
发布时间:2019-05-10

本文共 27072 字,大约阅读时间需要 90 分钟。

1) What is a Bash script

A Bash script is a plain text file which contains a series of commands. These commands are a mixture of commands we would normally type ouselves on the command line (such as ls or cp for example) and commands we could type on the command line but generally wouldn’t (you’ll discover these over the next few pages). An important point to remember though is:

Anything you can run normally on the command line can be put into a script and it will do exactly the same thing. Similarly, anything you can put into a script can also be run normally on the command line and it will do exactly the same thing.

You don’t need to change anything. Just type the commands as you would normally and they will behave as they would normally. It’s just that instead of typing them at the command line we are now entering them into a plain text file. In this sense, if you know how to do stuff at the command line then you already know a fair bit in terms of Bash scripting.

2) Variables

2-1) Special variables

  • $0 - The name of the Bash script
  • $1-9 - The first 9 arguments to the Bash script
  • $# - How many arguments were passed to the Bash script
  • $@ - All the arguments supplied to the Bash script
  • $? - The exit status of the most recently run process
  • $USER - The username of the user running the script
  • $HOSTNAME - The hostname of the machine the script is running on
  • $SECONDS - The number of seconds since the script was started
  • $RANDOM - Returns a different random number each time is it referred to
  • $LINENO - Returns the current line number in the Bash script

2-2) Setting our own variables

#!/bin/bash# A simple variable examplemyvariable=Helloanothervar=Fredecho $myvariable $anothervarechosampledir=/etcls $sampledir

When we enclose our content in quotes we are indicating to Bash that the contents should be considered as a single item. You may use single quotes(‘) or double quotes(“”)

* Single quotes will treat every character literally
* Double quotes will allow you to do substitution (that is include variables within the settting of the value)

myvar='Hello World'echo $myvarHello Worldnewvar="More $myvar"echo $newvarMore Hello Worldnewvar='More $myvar'echo $newvarMore $myvar

2-3) Command substitution

Command substitution allows us to take the output of a command or program(what would normally be printed to the screen) and save it as the value of a variable. To do this we place it within brackets, preceded by a $ sign.

myvar=$(ls /etc | wc -l)echo There are $myvar entries in the directory /etc

Commmand substitution is nice and simple if the output of the command is a single word or line. if the output goes serveral lines then the newlines are simply removed and all the output ends up on a single line.

lsbin Documents Desktop ...Downloads public_html ...myvar=$( ls )echo $myvarbin Documents Desktop Downloads public_html ...

2-4) Exporting varibales

myvar=helloworldexport myvar...

When we export a variable is that we are telling Bash that every time a new process is created (to run another script or such) the make a copy of the variable and hand it over to the new process. So although the variables will have the same name they exist in separate process and so are unrelated to each other.

Exporting variables is a one way process. The original process may pass variables over to the new process but anything that process does with the copy of the variables has no impact on the original variables.

3) Input

If we would like to ask the user for input then we use a command called read. This command takes the input and will save it into a variable.

Let’s look at a simple example:

#!/bin/bash# Ask the user for their nameecho Hello, who am I talking to?read varnameecho It\'s nice to meet you $varname

3-1) More with read

You are able to alter the behaviour of read with a variety of command line options.(See the man page for read to see all of them.) Two commonly used options however are -p which allows you to specifiy a prompt and -s which makes the input silent. This can make it easy to ask for a username and password combination like the example below:

#!/bin/bash# Ask the user for login detailsread -p 'Username: ' uservarread -sp 'Password: ' passvarechoecho Thankyou $uservar we now have your login details

3-2) More variables

So for we’ve looked at a single word as input. We can do more than that however.

#!/bin/bash# Demonstrate how read actually worksecho What cars do you like?read car1 car2 car3echo Your first car was: $car1echo Your second car was: $car2echo Your third car was: $car3output:What cars do you like?Jaguar Maserati BentleyYour first car was: JaguarYour second car was: MaseratiYour third car was: BentleyWhat cars do you like?Jaguar Maserati Bentley LotusYour first car was: JaguarYour second car was: MaseratiYour third car was: Bentley Lotus

The general mechanism is that you can supply several variable name to read. Read will then take your input and split it on whitespace.

The first item will then be assigned to the first variable name, the second item to the second variable name and so on. if there are more items than variable names then the remaining items will all be added to the last variable name. If there are less items than variable naems then the remaining variable names will be set to blank or null.

3-3) Reading from STDIN

It’s common in Linux to pipe a series of simple, single purpose commands together to create a larger solution tailored to our exact needs.

Bash accommodates piping and redirection by way of special files. Each process gets it’s own set of files(one for STDIN, STDOUT and STDERR respectively) and they are linked when piping or redirection is invoked.

Each process gets the following files:
* STDIN - /proc//fd/0
* STDOUT - /proc//fd/1
* STDERR - /proc//fd/2

To make life more convenient the system creates some shortcuts for us:

* STDIN - /dev/stdin or /proc/self/fd/0
* STDOUT - /dev/stdout or /proc/self/fd/1
* STDERR - /dev/stderr or /proc/self/fd/2
fd in the paths above stands for file descriptor.

So if we would like to make our script able to process the data that is piped to it all we need to do is read the relevant file. All of the files mentioned above behave like normal file:

#!/bin/bash# A basic summary of my sales reportecho Here is a summary of the sales data:echo ====================================echocat /dev/stdin | cut -d' ' -f 2,3 | sort

Outputs:

cat salesdata.txtFred apples 20 November 4Susy oranges 5 November 7Mark watermelons 12 November 10Terry peaches 7 November 15cat salesdata.txt | ./summaryHere is a summary of the sales data:====================================apples 20oranges 5peaches 7watermelons 12

So we now have 3 methods for getting input from the user:

* Command line arguments
* Read input during script execution
* Accept data input has been redirection into the bash script vis STDIN

4) Arithmetic

4-1) Let

let is a builtin function of Bash that allows us to do simple arithmetic.

let 
#!/bin/bash# Basic arithmetic using letlet a=5+4echo $a # 9let "a = 5 + 4"echo $a # 9let a++echo $a # 10let "a = 4 * 5"echo $a # 20let "a = $1 + 30"echo $a # 30 + first command line argument

4-2) Expr

Expr is similar to let except instead of saving the result to a variable it instead prints the answer. Unlike let you don’t need to enclose the expression in quotes. You also must have spaces between the items of the expression. It is also common to use expr within command substitution to save the output to a variable.

#!/bin/bash# Basic arithmetic using exprexpr 5 + 4expr "5 + 4"expr 5+4expr 5 \* $1expr 11 % 2a=$( expr 10 - 3 )echo $a # 7

Outputs:

95 + 45+46017

Notes:

* If we do put quotes around the expression then the expression will not be evaluated but printed instead.
* If we do not put spaces between the items of the expression then the expression will not be evaluated but printed instead.
* Some characters have a special meaning to Bash so we have to escape them (put a backslash in front of ) to remove their special meaning.
* This time we’re using the expr within command substitution in order to save the result to the variable a.

4-3) Double Parentheses

In the section on Variables we saw that we can save the output of a command easily to a variable. It turns out that this mechanism is also able to do basic arithmetic for us if we tweak the syntax a little. We do so by using double brackets like so:

$((expression))

Here’s an example to illustrate:

#!/bin/bash# Basic arithmetic using double parenthesesa=$(( 4 + 5 ))echo $a # 9a=$((3+5))echo $a # 8b=$(( a + 3 ))echo $b # 11b=$(( $a + 4 ))echo $b # 12(( b++ ))echo $b # 13(( b += 3 ))echo $b # 16a=$(( 4 * 5 ))echo $a # 20Outputs:981112131620

So as you can see double parentheses is quite flexible in how you format it’s expression. This is part of why we prefer this method. As double parentheses is builtin to Bash it also runs slightly efficiently.

4-4) Length of a Variable

This isn’t really arithmetic but it can be quite useful. If you want to find out the length of a variable (how many characters) you can do the following:

${
#vaiable}

Here’s an example:

#!/bin/bash# Show the length of a variable.a='Hello World'echo ${#a} # 11b=4953echo ${#b} # 4Outputs:114

4-4) Summary

  • let - Make a variable equals to an expression
  • expr - print out the result of the expression
  • $(()) - Return the result of the expression
  • ${#var} - Return the length of the variable var

Important Concepts:

* Arithmetic - There are several ways in which to do arithmetic in Bash scripts. Double parentheses is the preferred method.
* Formatting - When doing arithmetic, the presence or absence of space (and quotes) is often important.

5) If Statements

Bash if statements are very useful. In this section of our Bash script tutorial you will learn the ways you may use if statements in your Bash script to help automate tasks.

5-1) Basic If Statements

A basic if statement effectively say, if a particular test is true, then perform a given set of actions. if it is not true then don’t perform those actions. If follows the format below:

if [ 
]then
fi

Here’s an example:

#!/bin/bash# Basic if statementif [ $1 -gt 100 ]thenecho Hey that\'s a large number.pwdfidate

Tips: It is always good practice to test your script with input that cover the different scenarios that are possible.

5-2) Test

The square brackets ([]) in the if statement above are actually a reference to the command test. This means that all of the operators that test allows may be used in here as well. Look up the man page for test to see all of the possible operators, but some of the more common ones are list below:

Operator Description
! EXPRESSION The EXPRESSION is false.
-n STRING The length of STRING is greater than zero.
-z STRING The lengh of STRING is zero (ie it is empty).
STRING1 = STRING2 STRING1 is equal to STRING2
STRING1 != STRING2 STRING1 is not equal to STRING2
INTEGER1 -eq INTEGER2 INTEGER1 is numerically equal to INTEGER2
INTEGER1 -gt INTEGER2 INTEGER1 is numerically greater than INTEGER2
INTEGER1 -lt INTEGER2 INTEGER1 is numerically less than INTEGER2
-d FILE FILE exists and is a directory.
-e FILE FILE exists.
-r FILE FILE exists and the read permission is granted.
-s FILE FILE exists and it’s size is greater than zero (ie. it is not empty).
-w FILE FILE exists and the write permission is granted.
-x FILE FILE exists and the execute permission is granted.

A few points to note:

* = is slightly different to -eq. [ 001 = 1 ] will return false as = does a string comparison(ie. character for character the same) whereas -eq does a numerical comparison meaning [ 001 -eq 1] will return true.
* When we refer to FILE above we are actually meaning path. Remember that a path may be absolute or relative and may refer to a file or a directory
* Because [] is just a reference to the command test we may experiment and trouble shoot with test on the command line to make sure our understanding of its behaviour is correct

test 001 = 1echo $?1test 001 -eq 1echo $?0touch myfiletest -s myfileecho $?1ls /etc > myfiletest -s myfileecho $?0
  • Perform a string based comparison. Test doesn’t print the result so instead we check it’s exit status which is what we will do on the next line
  • The variable $? holds the exit status of the previously run command. 0 means true (or success). 1 = false (or failure).

5-3) Nested If Statements

Here is an example:

#!/bin/bash# Nested if statementsif [ $1 -gt 100 ]then    echo Hey that is a large number.    if (( $1 % 2 == 0 ))    then        echo And is also an even number.    fifi

Let’s break it down:

* if (( $1 % 2 == 0 )) This is a ligth variation on the if statement. If we would like to check an expression then we may use the double brackets just like we did for variables.

Tips: You can nest as many if statement as you like but as a general rule of thumb if you need to nest more than 3 levels deep then you should probably have a think about reorganising your logic.

5-4) If Else

Sometimes we want to perform a certain set of actions if a statement is true, and another set of actions if it is false. We can accommodate this with the else mechanism

if [ 
]then
else
fi

Example:

#!/bin/bash# else exampleif [ $# -eq 1 ]then    nl $1else    nl /dev/stdinfi

5-5) If Elif Else

Sometimes we may have a series of conditions that may lead to different paths

if [ 
]then
elif [
] then
else
fi

Example:

#!/bin/bash# elif statementsif [ $1 -ge 18 ]then    echo You may go to the party.elif [ $2 == 'yes' ]then    echo You may go to the party but be back before midnight.else    echo You may not go to the party.fi

5-6) Boolean Operations

Sometimes we only want to do something if multiple conditions are met. Other times we would like to perform the action if one of several condition is met. We can accommodate these with boolean operators.

and - &&or - ||

Examples:

One:#!/bin/bash# and exampleif [ -r $1 ] && [ -s $1 ]then    echo This file is useful.fiTwo:#!/bin/bash# or exampleif [ $USER == 'bob' ] || [ $USER == 'andy' ]then    ls -alhelse    lsfi

5-7) Case Statements

Sometimes we may wish to take different paths based upon a variable matching a series of patterns.

case 
in
)
;;
)
;;esac

Example:

#!/bin/bash# case examplecase $1 in    start)        echo starting        ;;    stop)        echo stoping        ;;    restart)        echo restarting        ;;    *)        echo do not know        ;;esac

Now let’s look at a slightly more complex example where patterns are used a bit more.

disk_useage.sh#!/bin/bash# Print a message about disk useage.space_free=$( df -h | awk '{ print $5 }' | sort -n | tail -n 1 | sed 's/%//' )case $space_free in    [1-5]*)        echo Plenty of disk space available        ;;    [6-7]*)        echo There could be a problem in the near future        ;;    8*)        echo Maybe we should look at clearing out old files        ;;    9*)        echo We could have a serious problem on our hands soon        ;;    *)        echo Something is not quite right here        ;;esac

6) Loops

Bash loops are very useful. In this section of our Bash script tutorial we’ll look at the different loop formats available to us as well as discuss when and why you may want to use each of them

There are 3 basic loop structures in Bash scripting which we’ll look at below. There are also a few statements which we can use to control the loops operation.

6-1) While Loops

One of the easiest loops to work with is while loops.

while [ 
]do
done

Example:

#!/bin/bash# Basic while loopcounter=1while [ $counter -le 10 ]do    echo $counter    // Using the double brackets     // we can increase the value of counter by 1.    ((counter++)) doneecho All doneOutputs:12345678910All done

6-2) Until Loops

The until loop is quite similar to the while loop. The difference is that it will execute the commands within it until the test becomes true.

until [ 
]do
done

Example:

#!/bin/bash# Basic until loopcounter=1until [ $counter -gt 10 ]do    echo $counter    ((counter++))doneecho All done

6-3) For Loops

The for loop is a little bit different from the previous two loops.

It has the following syntax:

for var in 
do
done

The for loop will take each item in the list(in order, one after the other). assign that item as the value of the variable var, execute the commands between do and done then go back to the top, grab the next item in the list and then repeat over.

The list is defined as a series of strings, separated by spaces.
Example:

#!/bin/bash# Basic for loopnames='Stan Kyle Cartman'for name in $namesdo    echo $namedoneecho All done

6-4) Ranges

We can also process a series of numbers.

#!/bin/bash# Basic range in for loop// It's important when specifying a range like this that there // are no spaces present between the curly brackets. If there // are then it not be seen as a range but as a list of items.for value in {
1..5}do echo $valuedoneecho All doneOutput:12345

One of the more useful applications of for loop is in the processing of a set of files. To do this we may use wildcards. Let’s say we want to convert a series of .html files over to .php files.

#!/bin/bash# Make a php copy of any html filesfor value in $1/*.htmldo    cp $value $1/$( basename -s .html $value ).phpdone

6-5) Controlling Loops: Break and Continue

Break :

The break statement tells Bash to leave the loop straight away.

#!/bin/bash# Make a backup set of filesfor value in $1/*do    used=$( df $1 | tail -1 | awk '{ print $5 }' | sed 's/%//' )    if [ $used -gt 90 ]    then        echo Low disk space 1>&2    break    fi    cp $value $1/backup/done

Continue:

The continue statement tells Bash to stop running through this iteration of the loop and begin the next iteration.

#!/bin/bash# Make a backup set of filesfor value in $1/*do    if [ ! -r $value ]    then        echo $value not readable 1>&2        continue    fi    cp $value $1/backup/done

6-6) Select

The select mechanism allows you to create a menu system. It has the following format:

select var in 
do
done

When invoked it will take all the items in list (similar to other loops this is a spaces separated set of items) and present them on the screen with a number before each item. A prompt will be printed after this allowing user to select a number. When they select a number and hit enter the corresponding the value will be assigned to the variable var and the commands between the do and done will run. Once finished a prompt will be displayed again so the user may select another option.

A few points to note:

* No error checking is done. If the user enters something other than a number or a number not corresponding to an item then var becomes null(empty).
* If the user hits enter without entering any data then the list of options will be displayed again.
* The loop will be ended when an EOF signal is entered or the break statement is issued.
* You may change the system variable PS3 to change the prompt that is displayed.

Here is a simple example to illustrate it’s usage:

#!/bin/bash# A simple menu systemnames='Kyle Cartman Stan Quit'// Change the value of the system variable PS3 so that the // prompt is set to something a little more descriptive.PS3='Select character: 'select name in $namesdo    if [ $name == 'Quit' ]    then    break    fi    echo Hello $namedoneecho Bye

7) Functions

Functions in Bash Scripting are a great way to reuse code. In this section of our Bash scripting tutorial you’ll learn how they work and what you can do with them.

7-1) Basic Concept

Creating a function is fairly easy. They may be written in two different formats:

function_name () {    
}orfunction function_name {
}

A few points to note:

  • Either of the above methods of specifying a function is valid. Both operate the same and there is no advantage or disadvantage to one over the other. It’s really just personal preference.
  • In other programming languages it is common to have arguments passed to the function listed inside the brackets(). In Bash they are there only for decoration and you never put anything inside them.
  • The function definition(the actual function itself) must appear in the script before any calls to the function.

Let’s look at a simple example:

#!/bin/bash# Basic functionprint_something () {    echo Hello I am a function}print_somethingprint_something\Outputs:./function_example.shHello I am a functionHello I am a function

7-2) Passing Arguments

It is often case that we would like the function to process some data for us. We may send data to the function in a similar way to passing command line arguments to a script. We supply the arguments directly after the function name. Within the function they are accessible as 1, 2, etc.

#!/bin/bash# Passing arguments to a functionprint_something () {echo Hello $1}print_something Marsprint_something JupiterOutputs:Hello MarsHello Jupiter

7-3) Return Values

Most other programming language have the concept of a return value for function, a means for the function to send data back to the original calling location. Bash function does’t allow us to do this. They do however allow us to set a return status. Similar to how a program or command exits with an exit status which indicates whether it succeeded or not. We use the keyword return to indicate a return status.

#!/bin/bash# Setting a return status for a functionprint_something () {echo Hello $1return 5}print_something Marsprint_something Jupiterecho The previous function has a return value of $?Outputs:./return_status_example.shHello MarsHello JupiterThe previous function has a return value of 5

Let’s break it down:

  • The return status doesn’t have to be hardcoded. It may be a variable.
  • Remember that the variable $? contains the return status of the previously run command or function.

Notes:

  • Typically a return status of 0 indicates that everything went successfully. A non zero value indicates an error occurred.
  • If all you want to do is return a number then you can consider using the return status to achieve this. It is not it’s intended purpose but it will work.

One way to get around this is to use command substitution and have the function print the result (and only the result).

#!/bin/bash# Setting a return value to a functionlines_in_file () {cat $1 | wc -l}num_lines=$( lines_in_file $1 )echo The file $1 has $num_lines lines in it.Outputs:cat myfile.txtTomatoLettuceCapsicum./return_hack.sh myfile.txtThe file myfile.txt has 3 lines in it.

Let’s break it down:

  • This command will print the number of line in the file referred to by $1
  • We use the command substitution to take what would normally be printed to the screen and assign it to the variable num_lines.

7-4) Variable Scope

Scope refers to which part of a script can see which variables. By default a variable is global. This means that it is visible everywhere in the script. We may also create a variable as a local variable. When we create a local variable within a function. It is only visible within that function. To do that we use the keyword “local” in front of the variable the first time we set it’s value.

local var_name=

It is generally considered good practice to use the local variables within functions so as to keep everything within the function contained. This way variables are safer from being inadvertently modified by another part of the script which happens to have a variable with the same name.

#!/bin/bash# Experimenting with variable scopevar_change () {local var1='local 1'echo Inside function: var1 is $var1 : var2 is $var2var1='changed again'var2='2 changed again'}var1='global 1'var2='global 2'echo Before function call: var1 is $var1 : var2 is $var2var_changeecho After function call: var1 is $var1 : var2 is $var2Outputs:./local_variables.shBefore function call: var1 is global 1 : var2 is global 2Inside function: var1 is local 1 : var2 is global 2After function call: var1 is global 1 : var2 is 2 changed again

Tips:

Always use local variables within functions. Use global variables as a last resort and consider if there is a better way to do it before using them.

7-5) Overriding Commands

It is possible to name a function as the same name as the command you would normally use on the command line. This allows us to create a wrapper. eg. Maybe every time we call the ls command in our script, what we actually want is ls -lh. We could do the following:

#!/bin/bash# Create a wrapper around the command lsls () {command ls -lh}ls

7-6) Import functions from another file

Sometimes you maybe want to use functions that defined in another script file. To solve this issue, you can use “.” or source keyword to import a file which the functions are defined in

Here is an example:

#!/bin/bash. /home/username/yourscript.sh # The file that you want to importorsource /home/username/yourscript.sh # The file that you want to import# do something ......

8) User Interface

This is the final section in the tutorial and I’d like to use it to discuss a very important topic (which is often neglected) the user interface.

When most people think about the user interface they think about the bits the end user see and how they interact with the tool. For Bash scripts I like to think about the layout and structure of the commends inside the script as well. Bash scripts are often small tools used to automate tedious and repeated tasks. They are always readable by the user and often modified to suit changing requirements. Therefore the ease with which the user may modify and extend the script is also very important.

8-1) TPut

TPut is a command which allows you to control the cursor on the terminal and the format of content that is printed. It is quite a powerful and complex tool so I’ll introduce some of the basics here but leave it up to you to do further research.

Here is an example printing a message in the middle of the screen.

#!/bin/bash# Print message in center of terminal# tput cols will tell us how many columns the terminal hascols=$( tput cols )# tput lines will tell us how many lines the terminal has.rows=$( tput lines )# Take all the command line arguments and assign them to a single variable messagemessage=$@# Find out how many characters in the string message.input_length=${#message}half_input_length=$(( $input_length / 2 ))middle_row=$(( $rows / 2 ))middle_col=$(( ($cols / 2) - $half_input_length ))# tput clear will clear the terminaltput clear# tput cup will place the cursor at the given row and column.tput cup $middle_row $middle_col# tput bold will make everything printed to the screen bold.tput boldecho $@# tput sgr0 will turn bold off (and any other changes we may have made)tput sgr0# Place the prompt at the bottom of the screen.tput cup $( tput lines ) 0

Outputs:

user@bash: ./center_message.sh Hello there                             Hello thereuser@bash:

转载地址:http://ieyvb.baihongyu.com/

你可能感兴趣的文章
给Blog加上雅虎通PingMe服务:和网站用户即时聊天
查看>>
顶级域名注册分布统计:2006年09月 .com .de .net .uk .cn
查看>>
雅虎通可以批量添加MSN用户了
查看>>
应届生如何应聘雅虎中国/阿里巴巴工作职位
查看>>
豆瓣“我上”:一个blog就是一本有趣的书
查看>>
速度比较:GMail/MSN/Yahoo!Mail
查看>>
搜索引擎来路关键词的挖掘:百度统计的高级分析报告导出获取来源关键词
查看>>
C/C++题目--拷贝构造函数概念
查看>>
C/C++题目--深复制与浅复制
查看>>
数据结构教程--李春葆版(总结)之线性表-顺序存储结构练习题
查看>>
数据结构教程--李春葆版(总结)之排序-插入排序
查看>>
centos7单用户模式修改root密码
查看>>
linux文件类型
查看>>
alias,which命令
查看>>
数组名和指针的区别
查看>>
栈和堆的具体区别
查看>>
如何判断一个点在矩形内
查看>>
析构函数何时被调用
查看>>
C++虚函数底层机制
查看>>
面试题:随机数生成、蓄水池抽样、海量数据、设计秒杀系统
查看>>