〇、简介
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
|