linux shell高级脚本,Shell 脚本编程(高级篇)

高级篇

一、处理用户输入

1. 读取脚本参数

Bash Shell 将命令行中传递给脚本的参数赋值给一组特殊的变量,叫做位置变量(positional parameters)。位置变量用 $number 的形式表示。

如 $0 表示脚本文件的名称,$1 表示脚本收到的第一个参数,$2 表示第二个参数,以此类推,直到 $9 表示第九个参数。

从第十个参数起,使用 ${number} 的形式。即第十个参数表示为 ${10}。

示例程序:

$ cat add.sh

#!/bin/bash

total=$[ $1 + $2 ]

echo "The first parameter is $1"

echo "The second parameter is $2"

echo "The total value is $total"

$ ./add.sh 2 5

The first parameter is 2

The second parameter is 5

The total value is 7

2. 参数检查

在 Shell 脚本中使用命令行参数时,一般需要先对传入的参数进行检查。如脚本执行时没有接收到预想的参数,往往会在执行过程中报出错误。如:

$ ./add.sh 2

./add.sh: line 3: 2 + : syntax error: operand expected (error token is " ")

The first parameter is 2

The second parameter is

The total value is

所以参数检查是写脚本时很有必要的步骤:

$ cat check_parameter.sh

#!/bin/bash

if [ -n "$1" ]

then

echo Hello $1, glad to meet you.

else

echo "Sorry, you did not identify youself"

fi

$ ./check_parameter.sh starky

Hello starky, glad to meet you.

$ ./check_parameter.sh

Sorry, you did not identify youself

3. 特殊参数变量

参数计数

上面有提到,应该在使用命令行参数前先检查其是否符合要求。对于接收多个参数的脚本,有时候需要获取命令行中输入的参数数量。

Shell 脚本中的 $# 变量保存了该脚本执行时接收到的参数的数量。如:

$ cat count_parameters.sh

#!/bin/bash

echo There were $# parameters supplied.

$ ./count_parameters.sh

There were 0 parameters supplied.

$ ./count_parameters.sh test

There were 1 parameters supplied.

$ ./count_parameters.sh test test

There were 2 parameters supplied.

通过 $# 变量的使用,可以将之前的 add.sh 脚本优化为以下形式:

$ cat add2.sh

#!/bin/bash

if [ $# -ne 2 ]

then

echo Usage: add2.sh a b

else

total=$[ $1 + $2 ]

echo The total is $total

fi

$ ./add2.sh

Usage: add2.sh a b

$ ./add2.sh 2

Usage: add2.sh a b

$ ./add2.sh 2 4

The total is 6

PS: 虽然 $# 变量表示脚本接收到的参数的数量,但是脚本接收到的最后一个参数并不能使用 ${$#} 表示,而是用 ${!#}

获取所有参数

某些情况下需要获取命令行提供的所有参数。除了通过 $# 变量使用循环,还可以直接使用另外两个特殊的变量。

$* 和 $@ 变量都可以包含命令行输入的所有参数。

其中 $* 变量接收所有参数并将它们保存在一个单一的字符串中。

$@ 变量接收所有参数并将它们保存在分开的字符串中。

即 $* 变量将收到的所有参数作为整体的一个参数对待,而 $@ 变量将收到的所有参数作为不同的多个对象,可以使用 for 命令进行遍历。

这两个变量的区别可以通过以下脚本来区分:

$ cat iterate_parameters.sh

#!/bin/bash

count=1

for param in "$*"

do

echo "\$* Parameter $count = $param"

count=$[ $count + 1 ]

done

echo

count=1

for param in "$@"

do

echo "\$@ Parameter $count = $param"

count=$[ count + 1 ]

done

$ ./iterate_parameters.sh rich barbara katie jessica

$* Parameter 1 = rich barbara katie jessica

$@ Parameter 1 = rich

$@ Parameter 2 = barbara

$@ Parameter 3 = katie

$@ Parameter 4 = jessica

4. shift 命令

shift 命令可以用来操作命令行参数,对它们进行整体的移位。

默认情况下,shift 命令会将所有的命令行参数整体的向左移动一个位置。

即 $3 变量的值移动到 $2,$2 变量的值移动到 $1。如:

$ cat shift.sh

#!/bin/bash

echo "The original parameters: $*"

shift 2

echo "Here's the new parameters: $*"

$ ./shift.sh 1 2 3 4 5

The original parameters: 1 2 3 4 5

Here's the new parameters: 3 4 5

二、函数

1. 函数定义

Bash Shell 脚本中的函数可以用以下两种格式定义:

function name {

commands

}

name() {

commands

}

具体示例如下:

$ cat func1.sh

#!/bin/bash

function func1 {

echo "This is an example of a function"

}

count=1

while [ $count -le 5 ]

do

func1

count=$[ $count + 1 ]

done

echo "This is the end of the loop"

func1

echo "Now this is the end of the script"

$ ./func1.sh

This is an example of a function

This is an example of a function

This is an example of a function

This is an example of a function

This is an example of a function

This is the end of the loop

This is an example of a function

Now this is the end of the script

2. 函数返回值

退出状态

默认情况下,某个函数的完成状态(即退出码)即是该函数中最后一条命令的退出码。

在该函数执行后,可以使用 $? 变量获取其退出状态码。

$ cat exit_status.sh

#!/bin/bash

func1() {

echo "trying to display a non-existent file"

ls -l badfile

}

echo "testing the function: "

func1

echo "The exit status is: $?"

$ ./exit_status.sh

testing the function:

trying to display a non-existent file

ls: badfile: No such file or directory

The exit status is: 1

因为函数 func1 中的最后一条命令 ls -l badfile 没有执行成功,所以函数执行完后,变量 $? 的值为 1 而不是 0

return 命令

Bash Shell 可以使用 return 命令指定函数退出时的状态值(整数)。

$ cat return.sh

#!/bin/bash

function db1 {

read -p "Enter a value: " value

echo "doubling the value"

return $[ $value *2 ]

}

db1

echo "The new value is $?"

$ ./return.sh

Enter a value: 32

doubling the value

The new value is 64

PS: 注意函数执行结束后需要立即使用 $? 获取其返回值,前面不能隔有其他命令;

使用 return 指定的退出码必须介于 0 到 255 之间

3. 函数输出

就像可以把命令的输出内容赋值给 Shell 变量一样,函数的输出同样也可以通过 variable=$(function_name) 的形式赋值给某个变量。

$ cat func2.sh

#!/bin/bash

function db1 {

read -p "Enter a value: " value

echo $[ $value * 2 ]

}

result=$(db1)

echo "The new value is $result"

$ ./func2.sh

Enter a value: 32

The new value is 64

4. 函数中的变量

向函数传递参数

Bash Shell 对待函数就像对待普通的脚本文件一样。我们可以向脚本程序传递参数,也可以以类似的方式向函数传递参数。

函数可以使用标准参数(如 $#)环境变量代表它从命令语句里接收到的参数。

如函数本身的名称由 $0 定义,$1 代表第一个参数,$# 代表接收到的参数的数目,$* 表示函数接收到的所有参数 ($1 $2 ...) ,"$@" 表示函数接收到的所有参数,且每一个参数都被双引号包裹 ("$1" "$2" ...)

$ cat parameter.sh

#!/bin/bash

function addem {

if [ $# -eq 0 ] || [ $# -gt 2 ]

then

echo -1

elif [ $# -eq 1 ]

then

echo $[ $1 + $1 ]

else

echo $[ $1 + $2 ]

fi

}

echo "Adding 10 and 15:"

value=$(addem 10 15)

echo $value

echo "Try adding just one number:"

value=$(addem 10)

echo $value

echo "Now trying adding no numbers:"

value=$(addem)

echo $value

echo "Finally, try adding three numbers:"

value=$(addem 10 15 20)

echo $value

$ ./parameter.sh

Adding 10 and 15:

25

Try adding just one number:

20

Now trying adding no numbers:

-1

Finally, try adding three numbers:

-1

上述脚本中的 addem 函数通过 $# 变量检查传递给它的参数的数量:

如果参数数量等于 0 或大于 2([ $# -eq 0 ] || [ $# -gt 2 ]),则返回 -1 表示程序非正常退出。

如果参数数量等于 1([ $# -eq 1 ]),则返回两倍于该参数的值($[ $1 + $1 ])。

如果参数数量等于 2([ $# -eq 2 ]),则返回这两个参数的加和($[ $1 + $2 ])

全局变量与局部变量

变量的作用域是一个很容易引起问题的点。

函数中定义的变量可以拥有区别于普通变量的作用域,即它们可以对脚本中的其他部分“不可见”。

函数使用两种类型的变量:

全局变量

局部变量

全局变量是在整个脚本中都保持有效的变量。默认情况下,Shell 脚本中的任何变量都是全局变量。

$ cat global.sh

#!/bin/bash

function db1 {

value=$[ $value * 2 ]

}

read -p "Enter a value: " value

db1

echo "The new value is: $value"

$ ./global.sh

Enter a value: 24

The new value is: 48

区别于函数中的全局变量,任何只在函数内部生效的变量可以声明为局部变量,只需要在变量的声明前面加上 local 关键字即可。

$ cat local.sh

#!/bin/bash

function func1 {

local temp=$[ $value + 5 ]

result=$[ $temp * 2 ]

}

temp=4

value=6

func1

echo "The result is $result"

echo "The temp value is $temp"

$ ./local.sh

The result is 22

The temp value is 4

由于使用了 local 关健字指定函数内部的 $temp 变量为局部变量,所以函数 func1 中 $temp 变量值的变化(变为 11)并不影响函数外部 $temp 变量的值(仍为 4)。

5. 函数递归

这里用一个计算阶乘的示例简单说明下 Shell 脚本中的函数递归。

$ cat factorial.sh

#!/bin/bash

function factorial {

if [ $1 -eq 1 ]

then

echo 1

else

local temp=$[ $1 - 1 ]

local result=$(factorial $temp)

echo $[ $result * $1 ]

fi

}

read -p "Enter value: " value

result=$(factorial $value)

echo "The factorial of $value is: $result"

$ ./factorial.sh

Enter value: 4

The factorial of 4 is: 24

6. 库

函数的使用可以减少脚本中的重复代码。即可以在脚本的其他部分直接使用函数名调用函数,完成该函数定义的功能,而无需再重新输入一遍定义该函数的大段语句。

这种形式的代码复用可以扩展到多个脚本文件。Bash Shell 允许用户创建库文件,其他 Shell 脚本可以通过引用该库文件使用其中定义的函数。

示例如下:

$ cat myfuncs

function addem {

echo $[ $1 + $2 ]

}

function multem {

echo $[ $1 * $2 ]

}

function divem {

if [ $2 -ne 0 ]

then

echo $[ $1 / $2 ]

else

echo -1

fi

}

$ cat use_myfuncs.sh

. ./myfuncs

value1=10

value2=5

result1=$(addem $value1 $value2)

result2=$(multem $value1 $value2)

result3=$(divem $value1 $value2)

echo "The result of adding them is: $result1"

echo "The result of multiplying them is: $result2"

echo "The result of dividing them is: $result3"

$ ./use_myfuncs.sh

The result of adding them is: 15

The result of multiplying them is: 50

The result of dividing them is: 2

其中 myfuncs 库文件中分别定义了 addem multem divem 三个函数,use_myfuncs.sh 脚本用来引用 myfuncs 库并使用其中定义的函数(这两个文件都需要有执行权限)。

重点在于 use_myfuncs.sh 脚本中的第一行命令 . ./myfuncs。其中第一个 . 是 source 命令的缩写。

source 命令的作用是在当前语境下调用另一个脚本,而不是创建一个新的 Shell 会话。这样 myfuncs 中的函数就可以直接被 use_myfuncs.sh 脚本使用。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值