一. 什么是Shell
Shell是一个命令行解释器,它为用户提供了一个面向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。
Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令的方式称为批处理(Batch),用户事先写一个Shell脚本(Script),其中有很多条命令,让Shell一次把这些命令执行完,而不必一条一条地敲命令。Shell脚本和编程语言很相似,也有变量和流程控制语句,但Shell脚本是解释执行的,不需要编译,Shell程序从脚本中一行一行读取并执行这些命令,相当于一个用户把脚本中的命令一行一行敲到Shell提示符下执行。
Shell还是一个功能相当强大的编程语言,易编写,易调试,灵活性较强。Shell是解释执行的脚本语言,在Shell中可以直接调用Linux系统命令。
Shell具体可描述为:外层应用程序是一些命令,是非机器语言,比如ls , useradd等;而内核则识别的是机器语言0和1,让Shell解释器当一个“中介”,由非机器语言通过Shell解释器向机器语言的转化,转化后内核将命令传递给硬件执行。更直白的说,Shell就是我们操控的Linux终端界面,输入命令得到想要的功能。
二. Shell分类
- 由于历史原因,UNIX系统上有很多种Shell:
- sh(Bourne Shell):由Steve Bourne开发,各种UNIX系统都配有sh。
- csh(C Shell):由Bill Joy开发,随BSD UNIX发布,它的流程控制语句很像C语言,支持很多Bourne Shell所不支持的功能:作业控制,命令历史,命令行编辑。
- ksh(Korn Shell):由David Korn开发,向后兼容sh的功能,并且添加了csh引入的新功能,是目前很多UNIX系统标准配置的Shell,在这些系统上/bin/sh往往是指向/bin/ksh的符号链接。
- tcsh(TENEX C Shell):是csh的增强版本,引入了命令补全等功能,在FreeBSD、MacOS X等系统上替代了csh。
- bash(Bourne Again Shell):由GNU开发的Shell,主要目标是与POSIX标准保持一致,同时兼顾对sh的兼容,bash从csh和ksh借鉴了很多功能,是各种Linux发行版标准配置的Shell,在Linux系统上/bin/sh往往是指向/bin/bash的符号链接。虽然如此,bash和sh还是有很多不同的,一方面,bash扩展了一些命令和参数,另一方面,bash并不完全和sh兼容,有些行为并不一致,所以bash需要模拟sh的行为:当我们通过sh这个程序名启动bash时,bash可以假装自己是sh,不认扩展的命令,并且行为与sh保持一致。
bash示例:
[root@localhost ~]# vim /etc/passwd # 其中最后一列显示了用户对应的shell类型 root:x:0:0:root:/root:/bin/bash nobody:x:65534:65534:nobody:/nonexistent:/bin/sh syslog:x:101:103::/home/syslog:/bin/false itcast:x:1000:1000:itcast,,,:/home/itcast:/bin/bash ftp:x:115:125:ftp daemon,,,:/srv/ftp:/bin/false
用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程。以前学过的cd、alias、umask、exit等命令即是内建命令,凡是用which命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册,要在man手册中查看*内建命令*,应该执行
itcast$ man bash-builtins
如export、shift、if、eval、[、for、while等等。内建命令虽然不创建新的进程,但也会有Exit Status,通常也用0表示成功非零表示失败,虽然内建命令不创建新的进程,但执行结束后也会有一个状态码,也可以用特殊变量$?读出。
本文主要介绍的是Bourne Again Shell ,也就是Bash。Bash 是大多数Linux 系统默认的 Shell。
本文摘要
本文主要介绍 Linux Shell
编程的基础知识,包含下面 8 个方面:
- Shell 编程概述
- Shell 关键字
- Shell 变量
- Shell 运算
- Shell 语句
- Shell 函数
- Shell 调试
- Shell 易错点
Shell 编程概述
在 Linux 下有一门脚本语言叫做:Shell 脚本,这个脚本语言可以帮助我们简化很多工作,例如编写自定义命令等,所以还是很有必要学习它的基本用法的,一个简单的 hello.sh
脚本像下面这样,第一行 #!/bin/bash
标识该 Shell 脚本由哪个 Shell 解释:
#!/bin/bash
echo "Hello World!"123
赋予权限才可以执行:
# 赋予可执行权限
chmod a+x hello.sh
# 执行
./hello.sh
# 结果
Hello World!
1. 编写 Shell 脚本 2. 赋予可执行权限 3. 执行,调试
下面来介绍具体的语法。
Shell 关键字
常用的关键字如下:
1. echo:打印文字到屏幕
2. exec:执行另一个 Shell 脚本
3. read:读标准输入
4. expr:对整数型变量进行算术运算
5. test:用于测试变量是否相等、 是否为空、文件类型等
6. exit:退出
看个例子:
#!/bin/bash
echo "Hello Shell"
# 读入变量
read VAR
echo "VAR is $VAR"
# 计算变量
expr $VAR - 5
# 测试字符串
test "Hello"="HelloWorld"
# 测试整数
test $VAR -eq 10
# 测试目录
test -d ./Android
# 执行其他 Shell 脚本
exec ./othershell.sh
# 退出
exit
运行前,你需要新建一个 othershell.sh
的文件,让它输出 I'm othershell
,并且中途需要一次输入,我这里输入的是 10:
Hello Shell
10
VAR is 10
5
I'm othershell
学习任何一门语言都要了解它的变量定义方法,Shell 也不例外。
Shell 变量
Shell 变量分为 3 种: 1. 用户自定义变量 2. 预定义变量 3. 环境变量
定义变量需要注意下面 2 点: 1. 等号前后不要有空格:NUM=10
2. 一般变量名用大写:M=1
使用 $VAR
调用变量:
echo $VAR1
1. 用户自定义变量
这种变量只支持字符串类型,不支持其他字符,浮点等类型,
常见有这 3 个前缀:
1. unset
:删除变量
2. readonly
:标记只读变量
3. export
:指定全局变量
一个例子:
#!/bin/bash
# 定义普通变量
CITY=SHENZHEN
# 定义全局变量
export NAME=cdeveloper
# 定义只读变量
readonly AGE=21
# 打印变量的值
echo $CITY
echo $NAME
echo $AGE
# 删除 CITY 变量
unset CITY
# 不会输出 SHENZHEN
echo $CITY
运行结果:
SHENZHEN
cdeveloper
1变量定义及赋值
[root@localhost ~]:~$ v1=hello
[root@localhost ~]:~$ echo $v1
hello
但是要注意的是,赋值处必须为一个整体,不能有空格。
[root@localhost ~]:~$ v2=hello world
No command 'world' found, did you mean:
Command 'tworld' from package 'tworld' (universe)
world: command not found
想要包含空格,需要用单引号或双引号包围,如
[root@localhost ~]:~$ v2="hello world"
[root@localhost ~]:~$ echo $v2
hello world
[root@localhost ~]:~$ v3='hello world'
[root@localhost ~]:~$ echo $v3
hello world
2、单引号(')和双引号(")的区别
上面的示例中看到hello world
使用单引号或双引号包围再赋值给变量时,两者效果相同,但是其中的区别在哪里?
[root@localhost ~]:~$ a="hello"
[root@localhost ~]:~$ b="$a world"
[root@localhost ~]:~$ echo $b
hello world
[root@localhost ~]:~$ c='$a world'
[root@localhost ~]:~$ echo $c
$a world
可以看到,单引号中的$a
保持原样输出。而双引号中的$a
会替换成其变量值。
3、``符号
这个符号在数字键1的左侧,与单引号很类似。但是其功能与单引号双引号都有不同。在该符号中的命令会被执行。
[root@localhost ~]:~$ d=`date`
[root@localhost ~]:~$ echo $d
Wed Dec 28 06:31:13 PST 2016
如果不想使用这个符号,可以用$()
替换
[root@localhost ~]:~$ e=$(date)
[root@localhost ~]:~$ echo $e
Wed Dec 28 06:31:48 PST 2016
4、命令行交互read
有时候我们希望在脚本运行时能根据用户的输入决定脚本后续执行逻辑,比如在安装插件的时候经常会让用户选择输入[N/Y]
的时候。 比如有一个脚本script_test.sh
read -p "Please input [Y/N]: " yn
if [ "$yn" == "N" -o "$yn" == "n" ]; then
echo "NO"
elif [ "$yn" == "Y" -o "$yn" == "y" ]; then
echo "YES"
fi
在运行时根据用户的输入决定if
分支的走向。运行结果如下
[root@localhost ~]:~$ sh script_test.sh
Please input [Y/N]: y
YES
read
命令的使用形式为
read [-pt] variable
参数p:后面可以接提示符
参数t:后面可以接秒数
例如,
read -p "please input your name" -t 5 name
表示将输入内容赋值给变量name
,用户有5秒钟的输入时间。
5、定义变量类型declare
默认情况下,变量的赋值内容都是字符类型的。例如下面的代码,我们期望的是输出一个求和值,但是输出的是一个求和表达式。
[root@localhost ~]:~$ sum=100+300+500
[root@localhost ~]:~$ echo $sum
100+300+500
如果想要输出求和后的值,可以使用declare命令。
[root@localhost ~]:~$ declare -i sum=100+300+500
[root@localhost ~]:~$ echo $sum
900
declare
命令的使用形式如下:
declare [-aixr] variable
参数a:将variable定义为数组
参数i:将variable定义为整型(integer)
参数x:将variable设置成环境变量,类似于export的作用
参数r:variable为readonly类型,值不能被更改
二、Shell中的集合类型
1、数组(array
)
(1)数组定义和赋值
数组中的元素用括号包围,各元素之间用空格隔开。例如
[root@localhost ~]:~$ array_name=(v0 v1 v2 v3)
可以重新设置指定元素的内容,如下所示
[root@localhost ~]:~$ array_name[2]=v22
[root@localhost ~]:~$ echo ${array_name[2]}
v22
(2)数组元素访问
输出该数组中所有元素:
[root@localhost ~]:~$ echo ${array_name[*]}
v0 v1 v22 v3
[root@localhost ~]:~$ echo ${array_name[@]}
v0 v1 v22 v3
数组元素下标从0开始,想要访问指定位置的元素,使用[]指定下标值,如下所示
[root@localhost ~]:~$ echo ${array_name[0]}
v0
[root@localhost ~]:~$ echo ${array_name[1]}
v1
[root@localhost ~]:~$ echo ${array_name[3]}
v3
[root@localhost ~]:~$ echo ${array_name[2]}
v2
[root@localhost ~]:~$ echo ${array_name[4]}
(3)获取数组长度
获取数组长度使用如下命令
[root@localhost ~]:~$ echo ${#array_name[@]}
4
[root@localhost ~]:~$ echo ${#array_name[*]}
4
获取数组中单个元素的长度使用如下命令
[root@localhost ~]:~$ echo ${#array_name[2]}
3
2、map
map
类型中存储的都是键值对。 在Shell中定义map
变量如下所示:
declare -A m=(["a"]="1" ["b"]="2")
输出所有的key
[root@localhost ~]:~$ echo ${!m[@]}
a b
输出所有的value
[root@localhost ~]:~$ echo ${m[@]}
1 2
输出指定key
对应的value
[root@localhost ~]:~$ echo ${m["a"]}
1
[root@localhost ~]:~$ echo ${m["c"]}
添加元素
[root@localhost ~]:~$ m["c"]="3"
[root@localhost ~]:~$ echo ${m["c"]}
3
map
中键值对的个数
[root@localhost ~]:~$ echo ${#m[@]}
3
2. 预定义变量
预定义变量常用来获取命令行的输入,有下面这些:
- $0 :脚本文件名
- $1-9 :第 1-9 个命令行参数名
- $# :命令行参数个数
- $@ :所有命令行参数
- $* :所有命令行参数
- $? :前一个命令的退出状态
- $$ :执行的进程 ID
一个例子:
#!/bin/bash
echo "print $"
echo "$0 = $0"
echo "$1 = $1"
echo "$2 = $2"
echo "$# = $#"
echo "$@ = $@"
echo "$* = $*"
echo "$$ = $$"
echo "$? = $?"1234567891011
执行./hello.sh 1 2 3 4 5
的结果:
print $
# 程序名
$0 = ./hello.sh
# 第一个参数
$1 = 1
# 第二个参数
$2 = 2
# 一共有 5 个参数
$# = 5
# 打印出所有参数
$@ = 1 2 3 4 5
# 打印出所有参数
$* = 1 2 3 4 5
# 进程 ID
$$ = 9450
# 之前没有执行其他命令或者函数
$? = 012345678910111213141516171819202122232425
3. 环境变量
环境变量默认就存在,常用的有下面这几个: 1. HOME:用户主目录 2. PATH:系统环境变量 PATH 3. TERM:当前终端 4. UID:当前用户 ID 5. PWD:当前工作目录,绝对路径
还是看例子:
#!/bin/bash
echo "print env"
echo $HOME
echo $PATH
echo $TERM
echo $PWD
echo $UID123456789
运行结果:
print env
# 当前主目录
/home/orange
# PATH 环境变量
/home/orange/anaconda2/bin:后面还有很多
# 当前终端
xterm-256color
# 当前目录
/home/orange
# 用户 ID
1000
Shell 变量就介绍到这里,下面来介绍 Shell 的变量运算。
三、Shell中的字符操作
在任何语言中对字符串的操作都是非常频繁的。字符串的操作主要包括,字符串截取,字符串替换等。 接下来的示例中,都以字符串https://www.zhihu.com/people/4k8k
作为初始字符串。
str="https://www.zhihu.com/people/4k8k"
1、字符串删除
删除前面的http://
[root@localhost ~]:~$ echo ${str#https://}
www.zhihu.com/people/4k8k
删除后面的dabokele
[root@localhost ~]:~$ echo ${str%/4k8k}
https://www.zhihu.com/people
#
从前往后截取,%
从后往前截取。
示例中表示将符合的最短数据删除,如果使用两个#
,或者两个%
,则表示将符合的最长数据删除。
2、字符串截取
可以从字符串的指定位置开始截取,同时可以指定截取的位数,如下所示:
[root@localhost ~]:~$ echo ${str:2} // 从第二位开始截取到最末尾,第一个字符下标为0
tps://www.zhihu.com/people/4k8k
[root@localhost ~]:~$ echo ${str:2:3} // 从第二位开始顺序截取三个字符
tps
[root@localhost ~]:~$ echo ${str:(-6):3} // 从倒数第六位开始,截取三个字符,最后一个字符下标为-1
e/4
3、字符串替换
将http
s替换成HTTP
[root@localhost ~]:~$ echo ${str/https/HTTP}
HTTP://www.zhihu.com/people/4k8k
- 使用一个斜杠(
/
)表示只替换第一个遇到的字符。 - 使用两个斜杠(
//
)则表示替换全部符合的字符。 - 使用
#
匹配以指定字符开头的字符串。 - 使用
%
匹配以指定字符开头的字符串。
[root@localhost ~]:~$ echo ${str/e/E}
https://www.zhihu.com/pEople/4k8k
[root@localhost ~]:~$ echo ${str//e/E}
https://www.zhihu.com/pEoplE/4k8k
[root@localhost ~]:~$ echo ${str/#h/H} // 匹配开头的那个h
Https://www.zhihu.com/people/4k8k
[root@localhost ~]:~$ echo ${str/e/E}
https://www.zhihu.com/pEople/4k8k
[root@localhost ~]:~$ echo ${str/%e/E} // 匹配最后那个E,前一个匹配中匹配的是people中的e
https://www.zhihu.com/people/4k8k
4、字符串默认值
假设以下这个场景,如果变量name
没有赋过值,则给一个默认值default
,否则使用指定的值。
[root@localhost ~]:~$ echo $name
[root@localhost ~]:~$ echo ${name-default}
default
[root@localhost ~]:~$ name="ckm"
[root@localhost ~]:~$ echo ${name-default}
ckm
但是,如果已经将变量name设置成“”,则结果如下:
[root@localhost ~]:~$ name=""
[root@localhost ~]:~$ echo ${name-default}
如果变量内容为“”或者变量未初始化则给默认值,可以在-
前加个冒号,使用:-
[root@localhost ~]:~$ name=""
[root@localhost ~]:~$ echo ${name-default}
[root@localhost ~]:~$ echo ${name:-default}
default
5、字符串拼接
字符串拼接如下所示
[root@localhost ~]:~$ echo "aaa""bbb"
aaabbb
[root@localhost ~]:~$ echo "aaa"$str
aaahttps://www.zhihu.com/people/4k8k
[root@localhost ~]:~$ echo "aaa$str"
aaahttps://www.zhihu.com/people/4k8k
6、字符串长度
求字符串长度用#
操作,如下所示
[root@localhost ~]:~$ echo ${#str}
33
7、字符串split成数组
在以空格为分隔符分割字符串成数组时操作最简单。
[root@localhost ~]:~$ s="a b c d e"
[root@localhost ~]:~$ a=($s)
[root@localhost ~]:~$ echo ${a[*]}
a b c d e
[root@localhost ~]:~$ echo ${a[2]}
c
所以,如果需要指定特定字符进行分割,而原字符串中又没有空格时,可以先将特定字符替换成空格,然后按照上述进行分割,如下所示,
[root@localhost ~]:~$ s="a,b,c,d,e"
[root@localhost ~]:~$ a=(${s//,/ })
[root@localhost ~]:~$ echo ${a[*]}
a b c d e
[root@localhost ~]:~$ echo ${a[2]}
c
如果字符串中本身已有空格,并且期望的分隔符不是空格,按如下方法进行分割。首先将IFS
变量替换成指定字符,分割后再将IFS
更新为原字符。
[root@localhost ~]:~$ s="a b,c,d,e"
[root@localhost ~]:~$ old_ifs="$IFS"
[root@localhost ~]:~$ s="a b,c,d,e"
[root@localhost ~]:~$ OLD_IFS="$IFS"
[root@localhost ~]:~$ IFS=","
[root@localhost ~]:~$ a=($s)
[root@localhost ~]:~$ IFS="$OLD_IFS"
[root@localhost ~]:~$ echo ${a[*]}
a b c d e
[root@localhost ~]:~$ echo ${a[0]}
a b
[root@localhost ~]:~$ echo ${#a[*]}
4
8、字符串包含
有时候需要判断字符串str1
中是否包含字符串str2
,使用=~
操作符。
str1="hello"
str2="ell"
if [[ $str1 =~ $str2 ]];then
echo "$str1 contains $str2"
fi
查看运行结果
[root@localhost ~]~$ sh script_test.sh
hello contains ell
四 Shell 运算
我们经常需要在 Shell 脚本中计算,掌握基本的运算方法很有必要,下面就是 4 种比较常见的运算方法,功能都是将 m + 1: 1. m=$[ m + 1 ] 2. m=expr $m + 1
# 用 “ 字符包起来 3. let m=m+1 4. m=$(( m + 1 ))
来看一个实际的例子:
#!/bin/bash
m=1
m=$[ m + 1 ]
echo $m
m=`expr $m + 1`
echo $m
# 注意:+ 号左右不要加空格
let m=m+1
echo $m
m=$(( m + 1 ))
echo $m
运行结果:
2
3
4
5
a)算术运算符
算术运算符的使用格式如下
a=10
b=20
val=expr $a + $b
常用的算术运算符包括
b)关系运算符 关系运算符的使用格式如下
a=10
b=20
$a -eq $b
常用的关系运算符包括
c)布尔运算符 常用的布尔运算符如下
d)字符串运算符 常用的字符串运算符如下
e)文件测试运算符 常用的文件测试运算符如下
了解了基本的运算方法,下面进一步来学习 Shell 的语句。
五 Shell 语句
Shell 语句跟高级语言有些类似,也包括分支,跳转,循环,下面就带着大家一个一个突破。
0、循环接收脚本参数shift
测试脚本如下:
echo '原始参数: ' $*
shift
echo 'shift后参数: ' $*
shift 2
echo 'shift 2后参数: ' $*12345
查看脚本运行结果
[root@localhost ~]:~$ sh script_test.sh a b c d e f g
原始参数: a b c d e f g
shift后参数: b c d e f g // 移除第一个参数a
shift 2后参数: d e f g // 继续移除前两个参数b和c
1. if 语句
这个跟高级语言的 if - else - if
类似,只是格式有些不同而已,也来看个例子吧:
#!/bin/bash
read VAR
# 下面这两种判断方法都可以,使用 [] 注意左右加空格
#if test $VAR -eq 10
if [ $VART -eq 10 ]
then
echo "true"
else
echo "false"
fi
2. case 语句
case 语句有些复杂,要注意格式:
case
表达式的使用格式如下
case $变量 in
"内容1")
程序1
;;
"内容2")
程序2
;;
*) #匹配其他所有情况
程序3
;;
esac
看一个示例,如果第一个参数为hello
,则打印hello world
。如果第一个参数是bye
,则打印bye bye
。如果是另外的情况,则输出该参数。
case $$1 in
"hello")
echo "hello world"
;;
"bye")
echo "bye bye"
;;
"*")
echo $1
;;
esac
运行结果
[root@localhost ~]:~$ sh script_test.sh hello
hello world
[root@localhost ~]:~$ sh script_test.sh bye
bye bye
[root@localhost ~]:~$ sh script_test.sh hehe
hehe
#!/bin/bash
read NAME
# 格式有点复杂,一定要注意
case $NAME in
"Linux")
echo "Linux"
;;
"cdeveloper")
echo "cdeveloper"
;;
*)
echo "other"
;;
esac
运行结果:
# 输入 Linux
Linux
Linux
# 输入 cdeveloper
cdeveloper
cdeveloper
# 输入其他的字符串
hello
other
3. for 循环
for … do … done for
循环的格式如下
for var in con1 con2 con3 ...
do
程序
done
下面这个示例循环打印输入参数列表
for arg in $*
do
echo $arg
done
运行结果如下
[root@localhost ~]:~$ sh script_test.sh a b c d e
a
b
c
d
e
(3)for … do … done的另一种形式 for
循环的另一种个数如下
for ((初始值; 目标值; 步长))
do
程序
done
循环输出1
到10
中的奇数
for ((i=1; i<=10; i=i+2))
do
echo $i
done
运行结果如下
[root@localhost ~]:~$ bash script_test.sh
1
3
5
7
9
4. while 循环
注意与 for 循环的区别:
(1)while do done, until do done while
循环的格式如下
while [ condition ]
do
程序
done
与while
循环相反的是until
循环。
until [ condition ]
do
程序
done
在while
循环中,当条件满足使,就执行其中的程序。而until
循环中,当条件不成立时就终止循环。
下面举例用两种循环来实现当输入为yes
时跳出循环。 a) while循环示例如下
while [ "$yn" != "yes" ]
do
read -p "Please input yes to stop: " yn
done
echo "Stop!"
运行结果
[root@localhost ~]:~$ sh script_test.sh
Please input yes to stop: no
Please input yes to stop: no
Please input yes to stop: yes
Stop!
b) until循环示例如下
until [ "$yn" == "yes" ]
do
read -p "Please input yes to stop: " yn
done
echo "Stop!"
运行结果如下
[root@localhost ~]:~$ sh script_test.sh
Please input yes to stop: no
Please input yes to stop: yes
Stop!
until 语句与上面的循环的不同点是它的结束条件为 1:
#!/bin/bash
i=0
# i 大于 5 时,循环结束
until [[ "$i" -gt 5 ]]
do
echo $i
i=$[ $i + 1 ]
done
6. break
Shell 中的 break
用法与高级语言相同,都是跳出循环,来看个例子:
#!/bin/bash
for VAR in 1 2 3
do
# 如何 VAR 等于 2 就跳出循环
if [ $VAR -eq 2 ]
then
break
fi
echo $VAR
done
运行结果:
11
7. continue
continue
用来跳过本次循环,进入下一次循环,再来看看上面的例子:
#!/bin/bash
for VAR in 1 2 3
do
# 如果 VAR 等于 2,就跳过,直接进入下一次 VAR = 3 的循环
if [ $VAR -eq 2 ]
then
continue
fi
echo $VAR
done
运行结果:
1
3
下面介绍 Shell 编程中比较重要的函数,好像每种编程语言的函数都很重要。
六 Shell 函数
函数可以用一句话解释:带有输入输出的具有一定功能的黑盒子,相信有过编程经验的同学不会陌生。那么,我们先来看看 Shell 中函数定义的格式。
1. 定义函数
有 3 种常见格式:
格式一:
function 函数名 () {
指令...
}
格式二:
function 函数名 {
指令...
}
格式三:
函数名 () {
指令...
}
例如:
#!/bin/bash
function hello_world(){
echo "hello world fun"
echo $1 $2
return 1
}
function hello_world{
echo "hello world fun"
echo $1 $2
return 1
}
hello()
{
echo "hello fun"
}
2. 调用函数
如何调用上面的 3 个函数呢?
# 1. 直接用函数名调用 hello 函数
hello
# 2. 使用「函数名 函数参数」来传递参数
hello_world 1 2 # 1 2就是传递的参数$1 $2这里是使用位置参数传递的
# 3. 使用「FUN=`函数名 函数参数`」 来间接调用
FUN=`hello_world 1 2`
echo $FUN
3. 获取返回值
如何获取 hello_world
函数的返回值呢?还记得 $?
吗?
hello_world 1 2
# $? 可用于获取前一个函数的返回值,这里结果是 1
echo $?
4. 定义本地变量
使用 local
来在函数中定义本地变量:
fun()
{
local x=1
echo $x
}
俗话说,程序 3 分靠写,7 分靠调,下面我们就来看看如何调试 Shell 程序。
七 Shell 调试
使用下面的命令来检查是否有语法错误:
sh -n script_name.sh1
使用下面的命令来执行并调试 Shell 脚本:
sh -x script_name.sh1
来看个实际的例子,我们来调试下面这个 test.sh
程序:
#!/bin/bash
for VAR in 1 2 3
do
if [ $VAR -eq 2 ]
then
continue
fi
echo $VAR
done
首先检查有无语法错误:
sh -n test.sh1
没有输出,说明没有错误,开始实际调试:
sh -x test.sh1
调试结果如下:
+ [ 1 -eq 2 ]
+ echo 1
1
+ [ 2 -eq 2 ]
+ continue
+ [ 3 -eq 2 ]
+ echo 3
3
其中带有 +
表示的是 Shell
调试器的输出,不带 +
表示我们程序的输出。
八 Shell 易错点
这里我总结了一些初学 Shell 编程容易犯的错误,大多都是语法错误:
1. []
内不能嵌套 ()
,可以嵌套 []
2. $[ val + 1 ]
是变量加 1 的常用方法
3. []
在测试或者计算中里面的内容最好都加空格
4. 单引号和双引号差不多,单引号更加严格,双引号可以嵌套单引号
5. 一定要注意语句的格式,例如缩进
总结
本文主要介绍了 Shell 编程的基础知识,一篇文章不可能面面俱到,大家有不懂的还希望多多用搜索引擎,尽量养成自学的好习惯,谢谢阅读,一定要实践哦 :)