快速了解和学习Unix/Linux下Shell(五)

Tags: linux shell bash

这篇文章是快速了解和学习Unix/Linux下Shell的第四部分,前几部分参考:

  1. 快速了解和学习Unix/Linux下Shell(一)

  2. 快速了解和学习Unix/Linux下Shell(二)

  3. 快速了解和学习Unix/Linux下Shell(三)

  4. 快速了解和学习Unix/Linux下Shell(四)

一、循环语句

shell支持以下循环语句:

  1. for循环

  2. while循环

  3. until循环

1. for循环

for循环的格式如下:

for 变量 in 列表
do
    command1
    command2
    ...
    commandN
done

列表是一组值(每个值通过空格分隔)组成的序列或者字符串。in列表是可选的,如果不用它,for循环使用命令行的位置参数。

示例1:

for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done

输出:

The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5

示例2,输出字符串中的字符:

for str in 'This is a string'
do
echo $str
done

示例3,输出当前目录下的所有bash开头的隐藏文件:

#!/bin/bash

for FILE in $HOME/.bash*
do
echo $FILE
done

输出:

/fourybte/.bash_history
/fourybte/.bash_logout
/fourybte/.bash_profile
/root/.bashrc

2.while循环

while循环是判断测试条件是否为true来决定是否执行一系列命令。其格式为:

while command
do
   Statement(s) to be executed if command is true
done

下面例子的while循环表示:

  1. counter初始化为0

  2. 判断counter是否小于5

  3. 是,则将counter+1后输出,然后继续循环

  4. 否,则结束循环

counter=0
while [ $counter-lt 5 ]
do
counter='expr $counter+1'
echo $counter
done

输出:

1
2
3
4
5

while循环也可用于读取键盘输入。下面的例子中,输入信息被设置为变量FILM,按回车结束输入,按<Ctrl-D>结束命令。

echo 'type <CTRL-D> to terminate'
echo -n 'enter your most liked film: '
while read FILM
do
echo "Yeah! great film the $FILM"
done

输出:

type <CTRL-D> to terminate
enter your most liked film: Sound of Music
Yeah! great film the Sound of Music

3、until循环

until循环是当测试条件没满足时执行循环体中的一系列命令,当测试条件满足时退出循环,until循环的格式为:

until test
do
   Statement(s) to be executed until command is true
done

test为条件表达式,如果返回值为false,则继续执行循环体内的语句,否则结束循环。

示例1,输出0-9的数字:

#!/bin/bash

a=0

until [ ! $a -lt 10 ]
do
echo $a
a=`expr $a + 1`
done

输出:

0
1
2
3
4
5
6
7
8
9

3、break和continue命令

像大多数编程语言一样,Shell在循环过程中也可以使用break和continue跳出循环。

3.1 break

break命令强制结束循环,当遇到break指令时,后续未执行会从当前循环体跳出,后续循环将不再执行,如下例:

#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5, game is over!"
break
;;
esac
done

上面的循环测试用户输入,如果输入的值是1,2,3,4,5之一,将继续循环接受用户输入,否则跳出循环结束当前脚本。

在多层嵌套循环中,break 命令后面还可以跟一个整数"break n",表示跳出第几层循环。例如:

#!/bin/bash

for var1 in 1 2 3
do
for var2 in 0 5
do
if [ $var1 -eq 2 -a $var2 -eq 0 ]
then
break 2 #直接跳出2层循环,因为循环就2层嵌套,所以会结束脚本
else
echo "$var1 $var2"
fi
done
done


3.2 continue命令

continue会结束当前的这个循环进行下一次循环,当前continue后的代码将不会执行,如:

#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5!"
continue
echo "Game is over!"
;;
esac
done

上例,用户输入的信息不是1,2,3,4,5中的任何一个时,并不会终止循环,因此"game is over"永远不会输出。而且脚本也永远不会停止,除非按下Ctrl-D强行终止脚本。

与break相同,continue也可以跟一个数字代表跳出第几层循环continue n,如下例:

#!/bin/bash

NUMS="1 2 3 4 5 6 7"

for NUM in $NUMS
do
Q=`expr $NUM % 2`
if [ $Q -eq 0 ]
then
echo "Number is an even number!!"
continue
fi
echo "Found odd number"
done

输出:

Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number

二、函数

1. 函数定义

函数可以让将一个复杂的系统划分成若干模块,让程序结构更加清晰,提高代码复用率。Shell 也支持函数,Shell 函数必须先定义后使用,shell函数格式如下:

function_name () {
    list of commands
    [ return value ]
}

也可以在函数名前显示增加关键字function,来标识这段代码为一个函数,如:

function function_name () {
    list of commands
    [ return value ]
}

说明:

  • 函数返回值,可以显式增加return语句

  • 如果没有显示的return,shell会将最后一条命令的执行结果作为返回值。

  • Shell函数返回值只能是整数用来表示函数执行成功与否,一般而言0表示成功,其他值表示失败。

  • 如果 return 其他数据,比如一个字符串,往往会得到错误提示:“numeric argument required”。

  • 如果一定要让函数返回字符串,那么可以先定义一个变量,用来保存函数的计算结果,脚本在需要的时候访问这个变量来获得函数返回值。

示例1:

#!/bin/bash

# Define your function here
Hello () {
echo "Url is http://www.4byte.cn/learning/119983/kuai-su-liao-jie-he-xue-xi-unix-linux-xia-shell-wu.html"
}

# Invoke your function
Hello

输出:

Url is http://www.4byte.cn/learning/119983/kuai-su-liao-jie-he-xue-xi-unix-linux-xia-shell-wu.html

示例2,显示return:

#!/bin/bash
funWithReturn(){
    echo "The function is to get the sum of two numbers..."
    echo -n "Input first number: "
    
    read aNum
    echo -n "Input another number: "
    
    read anotherNum
    echo "The two numbers are $aNum and $anotherNum !"
    
    return $(($aNum+$anotherNum))
}
funWithReturn
# Capture value returnd by last command
ret=$?
echo "The sum of two numbers is $ret !"

函数返回值在调用该函数后通过 $? 来获得,运行结果为:

The function is to get the sum of two numbers...
Input first number: 25
Input another number: 50
The two numbers are 25 and 50 !
The sum of two numbers is 75 !

示例3,调用函数:

#!/bin/bash
# Calling one function from another
number_one () {
    echo "one"
    number_two
}

number_two () {
    echo "two"
}

number_one

结果:

one
two

像删除变量一样函数也可以删除,使用unset .f funcname 命令删除函数。如果你希望直接从终端调用自己编写的函数,可以将函数定义在用户主目录下的 .profile文件中,然后重新登录系统,即可使用。

2 函数参数

调用函数时可以向函数传递参数,在函数体内,可以通过$n的形式来获取参数的值。例如,$1表示第一个参数,$2表示第二个参数等等以此类推,需要注意的是,如果参数个数达到10个以上时,如10个,需要使用${10}来获得参数值。

示例:

#!/bin/bash
funWithParam(){
    echo "The value of the first parameter is $1 !"
    echo "The value of the second parameter is $2 !"
    echo "The value of the tenth parameter is $10 !"
    echo "The value of the tenth parameter is ${10} !"
    echo "The value of the eleventh parameter is ${11} !"
    echo "The amount of the parameters is $# !" # 参数个数
    echo "The string of the parameters is $* !" # 传递给函数的所有参数
}

funWithParam 1 2 3 4 5 6 7 8 9 34 73

下表是函数内可以使用的特殊变量:

特殊变量 说明
$# 传递给函数的参数个数。
$* 显示所有传递给函数的参数。
$@ 与$*相同,但是略有区别,请参考前几篇文章
$? 函数的返回值。


三、模块化的shell

当shell程序变大时,模块化是一个很好的选项,可以将大的shell脚本拆分成多个脚本文件单独维护,由主shell脚本统一包含并执行。Shell 中包含脚本可以使用:

. filename

或者

source filename

例如,创建两个脚本,一个是被调用脚本subscript.sh(不需要可执行权限),内容如下:

url="http://www.4byte.cn/learning/119983/kuai-su-liao-jie-he-xue-xi-unix-linux-xia-shell-wu.html"

一个是主文件 main.sh:

#!/bin/bash
. ./subscript.sh
echo $url

执行结果如下:

$chomd +x main.sh
./main.sh
http://see.xidian.edu.cn/cpp/view/2738.html
$

本文链接:http://www.4byte.cn/learning/119983/kuai-su-liao-jie-he-xue-xi-unix-linux-xia-shell-wu.html