Shell脚本编写简明教程



〇、简介

Shell 的作用是解释执行用户的命令,用户输入一条命令,shell 就行一条,这种方式成为交互式,还有另外一种方式,就是用户事先写一个 shell 脚本,包含很多命令,然后让 shell 一次性的进行执行,这种方式被称为“批处理方式”

一般我们在UNIX中使用的 shell 就是 bash 和 sh,当然也有其他 shell,在 UNIX 环境下可以使用 /etc/shells: valid login shells 命令来显示所有的 shell,想要切换,直接输入 shell 名即可


一、Shell 的启动

bash 启动脚本是 bash 启动时会自动执行的脚本,因此用户可以把一些环境变量的设置和 alias、umask 设置等放到启动脚本中,这样每次启动 shell 时都会自动生效

但是,启动 bash 的方法不同,执行启动脚本的步骤也不同


1、作为交互登录 Shell 启动,或者使用 --login 参数启动

交互 Shell 指的是用户在提示符下输入命令的 Shell,而不是执行脚本的 shell

这样启动 bash 会自动执行以下脚本:

  1. 执行 /etc/profil,系统中的每个用户登录时都执行,只有管理员可以修改

  2. 然后依次执行当前用户主目录的 ~/.bash_profile、~/.bash_login 和 ~/.profile 三个文件(如果存在的话)

  3. 在Shell 退出时,会执行 ~/.bash_logout 脚本(如果存在的话)


通常在 ~/.bash_profile 中会有下面几行:

这样,如果 ~/.bashrc 文件存在,还会调用这个脚本


2、以交互非登录 Shell 启动

比如在图形界面下开一个终端窗口,或者在登录 Shell 提示符下再输入 bash 命令,就得到一个交互非登录的 shell

这种 shell 在启动时自动执行 ~/.bashrc 脚本

如上面所讲,如果要在启动脚本中做某些设置,使它在图形终端窗口和字符终端的Shell中都起作用,最好就是在 ~/.bashrc 中设置。


如果终端或远程登录,那么登录 Shell 是该用户的所有其他进程的父进程,所以环境变量在登录 Shell 的启动脚本里设置一次就可以自动带到其他非登录 Shell 里,而本地变量、函数、 alias 等设置没有办法带到子Shell里,需要每次启动非登录Shell时设置一遍,所以就需要有非登录Shell的启动脚本,所以一般来说在 ~/.bash_profile 里设置环境变量,在 ~/.bashrc 里设置本地变量、函数、 alias 等。

如果你的Linux带有图形系统则不能这样设置,由于从图形界面的窗口管理器登录并不会产生登录Shell,所以环境变量也应该在 ~/.bashrc 里设置。


3、非交互式启动

为了执行脚本而 fork 出来的子 Shell 是非交互式 Shell,启动时执行的脚本文件有环境变量 BASH_ENV 定义,相当于执行下面的命令:

          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi


4、以 sh 命令启动

如果以 sh 命令启动 bash,bash 将模拟 sh 的行为

如果作为交互登录 shell 启动,则会一次执行:

  1. /etc/profile

  2. ~/.profile


如果作为交互式 Shell 启动,相当于执行

          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

以 #! /bin/sh 开头的脚本就是这种情况,不会运行任何脚本


二、Shell 如何执行命令

1、执行交互式命令

凡是使用 which 命令查不到程序文件所在位置的命令都是 shell 的内建命令,这些命令相当于 Shell 的进程中的一个函数,没有单独的 man 手册,可以使用下面的命令查看: man bash-builtins

对于非内建命令,Shell 会 fork 并 exec 该命令,创建一个新的进程,但是对于内建命令则不会,如 cd、alias、umask、exit、export、shift、if、eval、[、for、while 等命令都是内建命令

虽然内建命令不创建新的进程,但是也会有返回值,通常也用 0 表示调用成功,这个返回值被称为 Exit Status (状态码),可以使用特殊变量 $? 读出


2、执行脚本

shell 脚本中用 # 表示注释,相当于 C 语言中的 // 注释,但是#! 却表示该脚本使用 /bin/sh 解释执行,并不代表注释

如下例是一个简单的 shell 脚本:

将上面的代码保存在 .sh 文件中,即为一个 Shell 脚本

执行脚本只需要输入命令:./script.sh,这是 sh ./script.sh 命令的简写


执行上面的脚本的步骤为:

Shell脚本编写简明教程_第1张图片


三、Shell 的基本语法

1、变量

一般的,Shell 变量由全大写字母加下划线组成,有两种类型的 Shell 变量

(1)环境变量

环境变量可以从父进程传给子进程,因此 Shell 进程的环境变量可以从当前的 Shell 进程传给 fork 出来的子进程,使用 printenv 命令可以显示当前 Shell 进程的环境变量


(2)本地变量

只存在于当前 Shell 进程的变量,用set命令可以显示当前 Shell 进程中定义的所有变量(包括本地变量和环境变量)和函数


  • set

显示当前所有变量和函数


  • 变量的定义

环境变量是任何进程都有的概念,而本地变量是 Shell 所特有的概念,在 Shell 中,环境变量和本地变量的定义和用法相似,在 Shell 中定义或赋值一个变量可以使用下面的格式:

           VARNAME=value

等号两边是不能有空格的,否则就会被解释成命令或命令行参数


  • export -- 将变量导出为环境变量

任何一个变量定义后都仅存在于当前的 Shell 进程,是本地变量,用 export 命令可以把本地变量导出为环境变量,定义和导出环境变量也可以一步完成

           export VARNAME=value

当然也可以分两步:

           VARNAME=value

           export VARNAME


  • unset -- 删除变量

使用 unset 命令可以删除已经定义了的环境变量或本地变量

           unset VARNAME


  • echo -- 显示变量的值

使用 echo 命令可以显示变量的值


一般对于 VARNAME 变量,我们使用 ${VARNAME} 表示他的值,在不引起歧义的情况下,我们也可以直接使用 VARNAME 表示他的值


Shell 中的所有变量都是字符串,Shell中的变量也不需要先定义后使用,使用一个没有定义的变量,这个变量的值为空字符串


2、通配符 -- *、?、[]

Shell 中也有通配符,如下表:

如我们可以使用 ls  ch0[012].doc 命令查找文件,如果当前目录下有 ch00.doc 和 ch02.doc,ls 的参数会直接转换成这两个文件名,而不是一个匹配字符串


3、命令代换 -- `或 $()

由反引号(键盘上 ESC 键下面的,主键盘区左上角·/~)所引起来的也是一条命令,Shell 会首先执行反引号中的命令,然后将结果代换到原来的位置进行原命令的执行,如下面的命令:

           DATE=`date`

           echo $DATE

反引号和 $() 是一样的:

           DATE=$(date)

           echo $DATE


4、算术代换 -- $(())

Shell 会将 $(()) 中的 Shell 变量的取值转换成整数用于算术计算(其他情况下 Shell 都将变量视为字符串,无法进行算术计算)

           VAR=45

           echo $(($VAR+3))

会显示 48

$(()) 中只能进行 +、-、*、/ 和 () 运算,并且只能进行整数运算


5、转义字符 -- \

和 C 语言一样,Shell 中也需要转义字符,如 \ 、\$、\\、\`、\"


6、字符串 -- '、"

在 Shell 中单引号中的所有字符都被认为是普通的字符,所以不需要转义字符,如运行:

           $ echo '$SHELL'

会显示 $SHELL

           $ echo 'ABC\\'

会显示 ABC\\


双引号也将其中的字符串视为字面值,但是反引号、$、转义字符等等都保持原来的意义

如:

           $ echo "$SHELL"

会显示 /bin/bash


           $echo "`date`"

会显示 Sun Apr 20 11:22:06 CEST 2003


五、Shell 脚本语法

1、条件测试 -- test、[]

命令 test 或 [] 可以测试一个条件是否城里,如果测试结果为真,则该命令的 Exit Status 为0,如果测试结果为假,则命令的 Exit Status 为1(与C语言中正好相反)

由于 [] 中的 [ 实际上是一个命令,他后面的都是这个命令的参数,因此需要用空格隔开

如下例:

Shell脚本编写简明教程_第2张图片


常见测试命令如下所示:

Shell脚本编写简明教程_第3张图片


与 C 语言类似,测试条件之间还可以做与、或、非逻辑运算

Shell脚本编写简明教程_第4张图片


如:


需要注意的是,如果上例中的 VAR 变量没有被预先定义,那么就会被解释器展开为空字符串,整个命令就变成了:

           [ -d Desktop -a = 'abc' ] 

这就成了一个语法错误

为了避免这样的意外情况发生,一个好的 Shell 编程习惯总是把变量取值放到双引号之中:

Shell脚本编写简明教程_第5张图片


这样,虽然 VAR 没有被预先定义,但是命令还是被展开成了

            [ -d Desktop -a "" = 'abc' ]


2、分支控制 -- if、then、elif、else、fi

和 C 语言类似,在 Shell 中使用 if、then、elif、else、fi 几个命令实现分支控制,例如:

           if [ -f ~/.bashrc ]; then

                      .~/.bashrc

           fi


  • :

: 是一个特殊的指令,称为“空命令”,该命令不做任何事,但是 Exit Status 总是真,也可以使用 /bin/true 或 /bin/false 获得总是真或假的 Exit Status

           if :; then echo "always true"; fi

与下面的例子是一样的:

           if /bin/true; then echo "always true"; fi


  • read

我们也可以使用 read 命令等待用户键入一行字符串,存到一个 Shell 变量中

Shell脚本编写简明教程_第6张图片


  • &&、||

与C语言类似,Shell 也提供 && 与 ||

          test "$VAR" -gt 1 -a "$VAR" -lt 3

等价于

          test "$VAR" -gt 1 && test "$VAR" -lt 3


因为 && 操作的短路求值特性,很多 Shell 脚本喜欢写成:

         test "$(whoami)" != 'root' && (echo you are using a nonprivileged account; exit 1)


3、case、esac

case 命令类似于 C 语言的 switch/case 语句,esac 用来标志 case 语句块的结束

Shell 中的 case 语句不仅可以用来匹配数字,也可以用来匹配字符串和通配符


如下例,每个匹配分支都可以有若干条命令,末尾必须以;;结束

Shell脚本编写简明教程_第7张图片


下面的例子常常用在某服务的处理上,比如对于apache,我们可以输入 apache start 这个命令启动他,也可以使用 apache stop 这个命令终止他

Shell脚本编写简明教程_第8张图片


$0、$1 ... 等等指的是取命令的第0个参数、第1个参数。。。


4、for、do、done

Shell 脚本的 for 循环结构和 C 语言很不一样,他类似于某些编程语言的 foreach 循环

如下面的例子:


例子中,FRUIT 是一个变量,让这个变量依次取值为 apple、banana、pear 做循环,done 用来标志循环结束


如果目录下有 chap0、chap1、chap2 等文件,下面的循环将他们重命名为 chap0~ 、 chap1~ 、 chap2~ 等

          $ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done


5、while、do、done

while 的用法和 C 语言非常类似,比如下面是一个验证密码的脚本:

Shell脚本编写简明教程_第9张图片


我们也可以像 C 语言中那样控制 while 循环的循环次数

Shell脚本编写简明教程_第10张图片


6、一些特殊的变量

有很多变量是被 Shell 自动赋值的,如下表

Shell脚本编写简明教程_第11张图片


参数 $n 被称为“位置参数”

  • shift

shift 命令可以令位置参数左移,比如 shift 3 表示让 $4 变成 $1,$5 变成 $2,原来的 $1、$2就会被丢弃掉,而 $0 不移动

不带参数的 shift 命令相当于 shift 1


7、函数

Shell 中的函数定义中没有返回值也没有参数列表

如下面例子所示:

Shell脚本编写简明教程_第12张图片


注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号 } 写在同一行,命令末尾必须有;号。

Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的 main 函数,这才是整个脚本实际开始执行命令的地方)。


Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用 $0 、 $1 、 $2 等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的 $0 、 $1 、 $2 等变量。函数中可以用 return 命令返回,如果 return 后面跟一个数字则表示函数的Exit Status。

Shell脚本编写简明教程_第13张图片


六、Shell 脚本的调试方法

Shell提供了一些用于调试脚本的选项:

  • -n

读一遍脚本中的命令但是不执行,用于检查脚本中的语法错误

  • -v

一边执行脚本,一边将执行过的脚本命令打印到标准错误输出

  • -x

提供跟踪执行信息,将执行的每一条命令和结果依次打印出来


有三种方法使用这些选项:

  1. 在命令行提供参数   $ sh -x ./script.sh

  2. 在脚本开头提供参数    #! /bin/sh -x

  3. 在脚本中用 set 命令启用或禁用参数


Shell脚本编写简明教程_第14张图片


下面是我写的一个脚本,在打开终端的时候给出人性化的提示,并且询问是否将虚拟机中的重要文件保存在宿主机上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
# file: .init.sh
# author: 龙泉居士
# date: 2013-05-06 18:51
#
   
echo  "\033[44m`date`\033[0m"
echo  "\033[44mHello zeyu!\033[0m"
echo  ""
   
SAVE_OR_NOT= "no"
read  -p  "Do you want to save the Workspace [yes/no](no): "  SAVE_OR_NOT
if  "$SAVE_OR_NOT"  "yes"  ];
then  sh ~ /Workspace/ .save.sh 
fi
exit  1
1
2
3
4
5
6
7
8
9
10
11
#
# file: .save.sh
# author: 龙泉居士
# date: 2013-05-06 18:52
#
   
cd  ~ /Workspace
mysqldump -u root -p150102 zeyu_student > sql /zeyu_student .sql
mysqldump -u root -p150102 zeyu_custom > sql /zeyu_custom .sql
tar  -cvf Workspace. tar  *
mv  Workspace. tar  /mnt/hgfs/Debin/

然后在~/.bashrc 中添加下面的代码

1
2
3
4
# added by zeyu 2013/05/06
cd  Workspace
sh ~ /Workspace/ .init.sh
export  PATH=$PATH: /home/zeyu/Workspace
〇、简介

Shell 的作用是解释执行用户的命令,用户输入一条命令,shell 就行一条,这种方式成为交互式,还有另外一种方式,就是用户事先写一个 shell 脚本,包含很多命令,然后让 shell 一次性的进行执行,这种方式被称为“批处理方式”

一般我们在UNIX中使用的 shell 就是 bash 和 sh,当然也有其他 shell,在 UNIX 环境下可以使用 /etc/shells: valid login shells 命令来显示所有的 shell,想要切换,直接输入 shell 名即可


一、Shell 的启动

bash 启动脚本是 bash 启动时会自动执行的脚本,因此用户可以把一些环境变量的设置和 alias、umask 设置等放到启动脚本中,这样每次启动 shell 时都会自动生效

但是,启动 bash 的方法不同,执行启动脚本的步骤也不同


1、作为交互登录 Shell 启动,或者使用 --login 参数启动

交互 Shell 指的是用户在提示符下输入命令的 Shell,而不是执行脚本的 shell

这样启动 bash 会自动执行以下脚本:

  1. 执行 /etc/profil,系统中的每个用户登录时都执行,只有管理员可以修改

  2. 然后依次执行当前用户主目录的 ~/.bash_profile、~/.bash_login 和 ~/.profile 三个文件(如果存在的话)

  3. 在Shell 退出时,会执行 ~/.bash_logout 脚本(如果存在的话)


通常在 ~/.bash_profile 中会有下面几行:

这样,如果 ~/.bashrc 文件存在,还会调用这个脚本


2、以交互非登录 Shell 启动

比如在图形界面下开一个终端窗口,或者在登录 Shell 提示符下再输入 bash 命令,就得到一个交互非登录的 shell

这种 shell 在启动时自动执行 ~/.bashrc 脚本

如上面所讲,如果要在启动脚本中做某些设置,使它在图形终端窗口和字符终端的Shell中都起作用,最好就是在 ~/.bashrc 中设置。


如果终端或远程登录,那么登录 Shell 是该用户的所有其他进程的父进程,所以环境变量在登录 Shell 的启动脚本里设置一次就可以自动带到其他非登录 Shell 里,而本地变量、函数、 alias 等设置没有办法带到子Shell里,需要每次启动非登录Shell时设置一遍,所以就需要有非登录Shell的启动脚本,所以一般来说在 ~/.bash_profile 里设置环境变量,在 ~/.bashrc 里设置本地变量、函数、 alias 等。

如果你的Linux带有图形系统则不能这样设置,由于从图形界面的窗口管理器登录并不会产生登录Shell,所以环境变量也应该在 ~/.bashrc 里设置。


3、非交互式启动

为了执行脚本而 fork 出来的子 Shell 是非交互式 Shell,启动时执行的脚本文件有环境变量 BASH_ENV 定义,相当于执行下面的命令:

          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi


4、以 sh 命令启动

如果以 sh 命令启动 bash,bash 将模拟 sh 的行为

如果作为交互登录 shell 启动,则会一次执行:

  1. /etc/profile

  2. ~/.profile


如果作为交互式 Shell 启动,相当于执行

          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi

以 #! /bin/sh 开头的脚本就是这种情况,不会运行任何脚本


二、Shell 如何执行命令

1、执行交互式命令

凡是使用 which 命令查不到程序文件所在位置的命令都是 shell 的内建命令,这些命令相当于 Shell 的进程中的一个函数,没有单独的 man 手册,可以使用下面的命令查看: man bash-builtins

对于非内建命令,Shell 会 fork 并 exec 该命令,创建一个新的进程,但是对于内建命令则不会,如 cd、alias、umask、exit、export、shift、if、eval、[、for、while 等命令都是内建命令

虽然内建命令不创建新的进程,但是也会有返回值,通常也用 0 表示调用成功,这个返回值被称为 Exit Status (状态码),可以使用特殊变量 $? 读出


2、执行脚本

shell 脚本中用 # 表示注释,相当于 C 语言中的 // 注释,但是#! 却表示该脚本使用 /bin/sh 解释执行,并不代表注释

如下例是一个简单的 shell 脚本:

将上面的代码保存在 .sh 文件中,即为一个 Shell 脚本

执行脚本只需要输入命令:./script.sh,这是 sh ./script.sh 命令的简写


执行上面的脚本的步骤为:

Shell脚本编写简明教程_第15张图片


三、Shell 的基本语法

1、变量

一般的,Shell 变量由全大写字母加下划线组成,有两种类型的 Shell 变量

(1)环境变量

环境变量可以从父进程传给子进程,因此 Shell 进程的环境变量可以从当前的 Shell 进程传给 fork 出来的子进程,使用 printenv 命令可以显示当前 Shell 进程的环境变量


(2)本地变量

只存在于当前 Shell 进程的变量,用set命令可以显示当前 Shell 进程中定义的所有变量(包括本地变量和环境变量)和函数


  • set

显示当前所有变量和函数


  • 变量的定义

环境变量是任何进程都有的概念,而本地变量是 Shell 所特有的概念,在 Shell 中,环境变量和本地变量的定义和用法相似,在 Shell 中定义或赋值一个变量可以使用下面的格式:

           VARNAME=value

等号两边是不能有空格的,否则就会被解释成命令或命令行参数


  • export -- 将变量导出为环境变量

任何一个变量定义后都仅存在于当前的 Shell 进程,是本地变量,用 export 命令可以把本地变量导出为环境变量,定义和导出环境变量也可以一步完成

           export VARNAME=value

当然也可以分两步:

           VARNAME=value

           export VARNAME


  • unset -- 删除变量

使用 unset 命令可以删除已经定义了的环境变量或本地变量

           unset VARNAME


  • echo -- 显示变量的值

使用 echo 命令可以显示变量的值


一般对于 VARNAME 变量,我们使用 ${VARNAME} 表示他的值,在不引起歧义的情况下,我们也可以直接使用 VARNAME 表示他的值


Shell 中的所有变量都是字符串,Shell中的变量也不需要先定义后使用,使用一个没有定义的变量,这个变量的值为空字符串


2、通配符 -- *、?、[]

Shell 中也有通配符,如下表:

如我们可以使用 ls  ch0[012].doc 命令查找文件,如果当前目录下有 ch00.doc 和 ch02.doc,ls 的参数会直接转换成这两个文件名,而不是一个匹配字符串


3、命令代换 -- `或 $()

由反引号(键盘上 ESC 键下面的,主键盘区左上角·/~)所引起来的也是一条命令,Shell 会首先执行反引号中的命令,然后将结果代换到原来的位置进行原命令的执行,如下面的命令:

           DATE=`date`

           echo $DATE

反引号和 $() 是一样的:

           DATE=$(date)

           echo $DATE


4、算术代换 -- $(())

Shell 会将 $(()) 中的 Shell 变量的取值转换成整数用于算术计算(其他情况下 Shell 都将变量视为字符串,无法进行算术计算)

           VAR=45

           echo $(($VAR+3))

会显示 48

$(()) 中只能进行 +、-、*、/ 和 () 运算,并且只能进行整数运算


5、转义字符 -- \

和 C 语言一样,Shell 中也需要转义字符,如 \ 、\$、\\、\`、\"


6、字符串 -- '、"

在 Shell 中单引号中的所有字符都被认为是普通的字符,所以不需要转义字符,如运行:

           $ echo '$SHELL'

会显示 $SHELL

           $ echo 'ABC\\'

会显示 ABC\\


双引号也将其中的字符串视为字面值,但是反引号、$、转义字符等等都保持原来的意义

如:

           $ echo "$SHELL"

会显示 /bin/bash


           $echo "`date`"

会显示 Sun Apr 20 11:22:06 CEST 2003


五、Shell 脚本语法

1、条件测试 -- test、[]

命令 test 或 [] 可以测试一个条件是否城里,如果测试结果为真,则该命令的 Exit Status 为0,如果测试结果为假,则命令的 Exit Status 为1(与C语言中正好相反)

由于 [] 中的 [ 实际上是一个命令,他后面的都是这个命令的参数,因此需要用空格隔开

如下例:

Shell脚本编写简明教程_第16张图片


常见测试命令如下所示:

Shell脚本编写简明教程_第17张图片


与 C 语言类似,测试条件之间还可以做与、或、非逻辑运算

Shell脚本编写简明教程_第18张图片


如:


需要注意的是,如果上例中的 VAR 变量没有被预先定义,那么就会被解释器展开为空字符串,整个命令就变成了:

           [ -d Desktop -a = 'abc' ] 

这就成了一个语法错误

为了避免这样的意外情况发生,一个好的 Shell 编程习惯总是把变量取值放到双引号之中:

Shell脚本编写简明教程_第19张图片


这样,虽然 VAR 没有被预先定义,但是命令还是被展开成了

            [ -d Desktop -a "" = 'abc' ]


2、分支控制 -- if、then、elif、else、fi

和 C 语言类似,在 Shell 中使用 if、then、elif、else、fi 几个命令实现分支控制,例如:

           if [ -f ~/.bashrc ]; then

                      .~/.bashrc

           fi


  • :

: 是一个特殊的指令,称为“空命令”,该命令不做任何事,但是 Exit Status 总是真,也可以使用 /bin/true 或 /bin/false 获得总是真或假的 Exit Status

           if :; then echo "always true"; fi

与下面的例子是一样的:

           if /bin/true; then echo "always true"; fi


  • read

我们也可以使用 read 命令等待用户键入一行字符串,存到一个 Shell 变量中

Shell脚本编写简明教程_第20张图片


  • &&、||

与C语言类似,Shell 也提供 && 与 ||

          test "$VAR" -gt 1 -a "$VAR" -lt 3

等价于

          test "$VAR" -gt 1 && test "$VAR" -lt 3


因为 && 操作的短路求值特性,很多 Shell 脚本喜欢写成:

         test "$(whoami)" != 'root' && (echo you are using a nonprivileged account; exit 1)


3、case、esac

case 命令类似于 C 语言的 switch/case 语句,esac 用来标志 case 语句块的结束

Shell 中的 case 语句不仅可以用来匹配数字,也可以用来匹配字符串和通配符


如下例,每个匹配分支都可以有若干条命令,末尾必须以;;结束

Shell脚本编写简明教程_第21张图片


下面的例子常常用在某服务的处理上,比如对于apache,我们可以输入 apache start 这个命令启动他,也可以使用 apache stop 这个命令终止他

Shell脚本编写简明教程_第22张图片


$0、$1 ... 等等指的是取命令的第0个参数、第1个参数。。。


4、for、do、done

Shell 脚本的 for 循环结构和 C 语言很不一样,他类似于某些编程语言的 foreach 循环

如下面的例子:


例子中,FRUIT 是一个变量,让这个变量依次取值为 apple、banana、pear 做循环,done 用来标志循环结束


如果目录下有 chap0、chap1、chap2 等文件,下面的循环将他们重命名为 chap0~ 、 chap1~ 、 chap2~ 等

          $ for FILENAME in chap?; do mv $FILENAME $FILENAME~; done


5、while、do、done

while 的用法和 C 语言非常类似,比如下面是一个验证密码的脚本:

Shell脚本编写简明教程_第23张图片


我们也可以像 C 语言中那样控制 while 循环的循环次数

Shell脚本编写简明教程_第24张图片


6、一些特殊的变量

有很多变量是被 Shell 自动赋值的,如下表

Shell脚本编写简明教程_第25张图片


参数 $n 被称为“位置参数”

  • shift

shift 命令可以令位置参数左移,比如 shift 3 表示让 $4 变成 $1,$5 变成 $2,原来的 $1、$2就会被丢弃掉,而 $0 不移动

不带参数的 shift 命令相当于 shift 1


7、函数

Shell 中的函数定义中没有返回值也没有参数列表

如下面例子所示:

Shell脚本编写简明教程_第26张图片


注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号 } 写在同一行,命令末尾必须有;号。

Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的 main 函数,这才是整个脚本实际开始执行命令的地方)。


Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用 $0 、 $1 、 $2 等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的 $0 、 $1 、 $2 等变量。函数中可以用 return 命令返回,如果 return 后面跟一个数字则表示函数的Exit Status。

Shell脚本编写简明教程_第27张图片


六、Shell 脚本的调试方法

Shell提供了一些用于调试脚本的选项:

  • -n

读一遍脚本中的命令但是不执行,用于检查脚本中的语法错误

  • -v

一边执行脚本,一边将执行过的脚本命令打印到标准错误输出

  • -x

提供跟踪执行信息,将执行的每一条命令和结果依次打印出来


有三种方法使用这些选项:

  1. 在命令行提供参数   $ sh -x ./script.sh

  2. 在脚本开头提供参数    #! /bin/sh -x

  3. 在脚本中用 set 命令启用或禁用参数


Shell脚本编写简明教程_第28张图片


下面是我写的一个脚本,在打开终端的时候给出人性化的提示,并且询问是否将虚拟机中的重要文件保存在宿主机上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#
# file: .init.sh
# author: 龙泉居士
# date: 2013-05-06 18:51
#
   
echo  "\033[44m`date`\033[0m"
echo  "\033[44mHello zeyu!\033[0m"
echo  ""
   
SAVE_OR_NOT= "no"
read  -p  "Do you want to save the Workspace [yes/no](no): "  SAVE_OR_NOT
if  "$SAVE_OR_NOT"  "yes"  ];
then  sh ~ /Workspace/ .save.sh 
fi
exit  1
1
2
3
4
5
6
7
8
9
10
11
#
# file: .save.sh
# author: 龙泉居士
# date: 2013-05-06 18:52
#
   
cd  ~ /Workspace
mysqldump -u root -p150102 zeyu_student > sql /zeyu_student .sql
mysqldump -u root -p150102 zeyu_custom > sql /zeyu_custom .sql
tar  -cvf Workspace. tar  *
mv  Workspace. tar  /mnt/hgfs/Debin/

然后在~/.bashrc 中添加下面的代码

1
2
3
4
# added by zeyu 2013/05/06
cd  Workspace
sh ~ /Workspace/ .init.sh
export  PATH=$PATH: /home/zeyu/Workspace

你可能感兴趣的:(Linux,shell)