〇、简介
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 会自动执行以下脚本:
执行 /etc/profil,系统中的每个用户登录时都执行,只有管理员可以修改
然后依次执行当前用户主目录的 ~/.bash_profile、~/.bash_login 和 ~/.profile 三个文件(如果存在的话)
在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 启动,则会一次执行:
/etc/profile
~/.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 变量由全大写字母加下划线组成,有两种类型的 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语言中正好相反)
由于 [] 中的 [ 实际上是一个命令,他后面的都是这个命令的参数,因此需要用空格隔开
如下例:
常见测试命令如下所示:
与 C 语言类似,测试条件之间还可以做与、或、非逻辑运算
如:
需要注意的是,如果上例中的 VAR 变量没有被预先定义,那么就会被解释器展开为空字符串,整个命令就变成了:
[ -d Desktop -a = 'abc' ]
这就成了一个语法错误
为了避免这样的意外情况发生,一个好的 Shell 编程习惯总是把变量取值放到双引号之中:
这样,虽然 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 变量中
&&、||
与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 语句不仅可以用来匹配数字,也可以用来匹配字符串和通配符
如下例,每个匹配分支都可以有若干条命令,末尾必须以;;结束
下面的例子常常用在某服务的处理上,比如对于apache,我们可以输入 apache start 这个命令启动他,也可以使用 apache stop 这个命令终止他
$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 语言非常类似,比如下面是一个验证密码的脚本:
我们也可以像 C 语言中那样控制 while 循环的循环次数
6、一些特殊的变量
有很多变量是被 Shell 自动赋值的,如下表
参数 $n 被称为“位置参数”
shift
shift 命令可以令位置参数左移,比如 shift 3 表示让 $4 变成 $1,$5 变成 $2,原来的 $1、$2就会被丢弃掉,而 $0 不移动
不带参数的 shift 命令相当于 shift 1
7、函数
Shell 中的函数定义中没有返回值也没有参数列表
如下面例子所示:
注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号 } 写在同一行,命令末尾必须有;号。
Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的 main 函数,这才是整个脚本实际开始执行命令的地方)。
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用 $0 、 $1 、 $2 等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的 $0 、 $1 、 $2 等变量。函数中可以用 return 命令返回,如果 return 后面跟一个数字则表示函数的Exit Status。
六、Shell 脚本的调试方法
Shell提供了一些用于调试脚本的选项:
-n
读一遍脚本中的命令但是不执行,用于检查脚本中的语法错误
-v
一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
-x
提供跟踪执行信息,将执行的每一条命令和结果依次打印出来
有三种方法使用这些选项:
在命令行提供参数 $ sh -x ./script.sh
在脚本开头提供参数 #! /bin/sh -x
在脚本中用 set 命令启用或禁用参数
下面是我写的一个脚本,在打开终端的时候给出人性化的提示,并且询问是否将虚拟机中的重要文件保存在宿主机上:
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 会自动执行以下脚本:
执行 /etc/profil,系统中的每个用户登录时都执行,只有管理员可以修改
然后依次执行当前用户主目录的 ~/.bash_profile、~/.bash_login 和 ~/.profile 三个文件(如果存在的话)
在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 启动,则会一次执行:
/etc/profile
~/.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 变量由全大写字母加下划线组成,有两种类型的 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语言中正好相反)
由于 [] 中的 [ 实际上是一个命令,他后面的都是这个命令的参数,因此需要用空格隔开
如下例:
常见测试命令如下所示:
与 C 语言类似,测试条件之间还可以做与、或、非逻辑运算
如:
需要注意的是,如果上例中的 VAR 变量没有被预先定义,那么就会被解释器展开为空字符串,整个命令就变成了:
[ -d Desktop -a = 'abc' ]
这就成了一个语法错误
为了避免这样的意外情况发生,一个好的 Shell 编程习惯总是把变量取值放到双引号之中:
这样,虽然 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 变量中
&&、||
与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 语句不仅可以用来匹配数字,也可以用来匹配字符串和通配符
如下例,每个匹配分支都可以有若干条命令,末尾必须以;;结束
下面的例子常常用在某服务的处理上,比如对于apache,我们可以输入 apache start 这个命令启动他,也可以使用 apache stop 这个命令终止他
$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 语言非常类似,比如下面是一个验证密码的脚本:
我们也可以像 C 语言中那样控制 while 循环的循环次数
6、一些特殊的变量
有很多变量是被 Shell 自动赋值的,如下表
参数 $n 被称为“位置参数”
shift
shift 命令可以令位置参数左移,比如 shift 3 表示让 $4 变成 $1,$5 变成 $2,原来的 $1、$2就会被丢弃掉,而 $0 不移动
不带参数的 shift 命令相当于 shift 1
7、函数
Shell 中的函数定义中没有返回值也没有参数列表
如下面例子所示:
注意函数体的左花括号{和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号 } 写在同一行,命令末尾必须有;号。
Shell脚本中的函数必须先定义后调用,一般把函数定义都写在脚本的前面,把函数调用和其它命令写在脚本的最后(类似C语言中的 main 函数,这才是整个脚本实际开始执行命令的地方)。
Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调用函数时可以传任意个参数,在函数内同样是用 $0 、 $1 、 $2 等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外面的 $0 、 $1 、 $2 等变量。函数中可以用 return 命令返回,如果 return 后面跟一个数字则表示函数的Exit Status。
六、Shell 脚本的调试方法
Shell提供了一些用于调试脚本的选项:
-n
读一遍脚本中的命令但是不执行,用于检查脚本中的语法错误
-v
一边执行脚本,一边将执行过的脚本命令打印到标准错误输出
-x
提供跟踪执行信息,将执行的每一条命令和结果依次打印出来
有三种方法使用这些选项:
在命令行提供参数 $ sh -x ./script.sh
在脚本开头提供参数 #! /bin/sh -x
在脚本中用 set 命令启用或禁用参数
下面是我写的一个脚本,在打开终端的时候给出人性化的提示,并且询问是否将虚拟机中的重要文件保存在宿主机上:
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
|