文章目录
- 1.shell简介
-
- 1.1 什么是shell
- 1.2 shell脚本
- 1.3 运行shell脚本
- 1.4 shell注释
- 1.5 shell编写的基本步骤
- 2.shell变量
-
- 2.1 命名变量
- 2.2 使用变量
- 2.3 变量类型
- 2.4 变量操作
- 3.shell字符串
-
- 3.1 字符串类型
- 3.2 字符串操作
- 4.shell数组
-
- 4.1 定义数组
- 4.2 数组操作
- 5.shell传递参数
- 6.shell运算符
-
- 6.1 shell运算符种类
- 6.2 算数运算符
- 6.3 关系运算符
- 6.4 布尔运算符
- 6.5 逻辑运算符
- 6.6 字符串运算符
- 6.7 文件测试运算符
- 7.shell编程中的命令
-
- 7.1 echo命令
- 7.2 printf命令
- 7.3 test命令
- 8.shell流程控制
-
- 8.1 if else条件
- 8.2 case条件
- 8.3 for循环
- 8.4 while循环
- 8.5 until循环
- 9.shell函数
-
- 9.1 定义函数
- 9.2 参数定义
- 10.shell重定向
- 11.结尾
1.shell简介
1.1 什么是shell
什么是shell呢?shell是用C语言编写的程序,它是用户使用 Linux 的桥梁。Shell既是一种命令语言,又是一种程序设计语言。简单来说Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。也可以这样认为,linux中的shell就是linux内核的一个外层保护工具,并负责完成用户与内核之间的交互
1.2 shell脚本
shell脚本就是一种专门使用shell编写的脚本程序,它虽然没有C 、Java、Python等一系列高级语言功能强大,但是在服务器运维领域以及嵌入式开发领域,shell脚本具有举足轻重的地位。
shell脚本编程如同其他编程语言的一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以运行了,而linux下的shell种类众多,常用的用:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
- … …
在诸多linux发行版系统中,最常用的就是Bash,就是Bourne Again Shell,因为其能工提供环境变量以配置用户shell环境,支持历史记录、内置算数功能、支持通配符表达式等高效性能,将linux常用命令进行的简化,被广泛应用于Debian系列的linux发行版中。
1.3 运行shell脚本
运行shell脚本的方法有两种:
- 作为可执行程序运行
- 作为解释器参数运行
shell脚本编写如下,并将其保存为test.sh,进入存放此文件目录
代码语言:javascript复制#!/bin/bash
echo "Hello World"
当作为可执行程序运行时候
代码语言:javascript复制chmod x test.sh # 赋予可执行权限
./test.sh # 执行程序
当作为解释器参数运行时
代码语言:javascript复制/bin/sh test.sh # 执行命令
/bin/php test.php # 执行命令
1.4 shell注释
单行注释:和python注释相同,以#
号开头作为单行注释
# 这是一个注释
# author:ohuohuoo
# date:`date`
多行注释:如果在开发过程中,,遇到大段的代码需要临时注释起来,过一会儿又取消注释,可以将其定义为一个花括号的注释函数,也可以用多行注释
代码语言:javascript复制:<<EOF
注释内容...
注释内容...
注释内容...
EOF
# EOF可以换成其他符号
:<<E!
注释内容...
注释内容...
注释内容...
!
1.5 shell编写的基本步骤
- 建立shell文件
- 赋予shell文件可执行程序权限(使用chmod命令修改权限)
- 执行shell文件(直接运行赋予权限后的二进制文件)
2.shell变量
2.1 命名变量
shell编程中,定义变量是直接定义的,没有明确的数据类型,shel允许用户建立变量存储数据,但是将认为赋给变量的值都解释为一串字符,如下
代码语言:javascript复制cout=1 # 定义变量
name="ohuohuo" # 定义变量
echo $cout # 取变量值
echo $name # 取变量值
shell中,英文符号"$"
用于取变量值
注意点:shell编程的变量名的命名和其他语言一样,需要遵循一定的规则,规则如下
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
- 中间不能有空格,可以使用下划线(_)
- 不能使用标点符号
- 不能使用bash里的关键字(可用help命令查看保留关键字)
如下所示
有效的命令
代码语言:javascript复制NAME
LIBRARY_PATH
_var
var2
无效的命名
代码语言:javascript复制?var=123
user*name=ohuohuo
如果在变量中使用系统命令,需要加上 ” `”符号(ESC键下方),如下所示
代码语言:javascript复制DATE1=`date`
DATE2=$(date)
- 1
- 2
两者功能相同
2.2 使用变量
使用变量的时,用英文符号"$"
取变量值,对于较长的变量名,建议加上{ }
花括号,帮助解释器识别变量的边界,如下
name="test_name"
echo "My name is ${name}and you"
- 1
- 2
加上方括号时即所有便后面的语句不留空格,shell也会自动识别边界,默认添加一个空格
此外,已经定义过的变量,可以二次定义并重新被赋值覆盖上一次的变量值,这点如同其他语言
2.3 变量类型
shell编程中也同样存在变量类型,在运行shell时会同时存在三种变量
- 局部变量:在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
- 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,必要的时候shell脚本也可以定义环境变量
- shell变量:由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,不同类型的变量保证了shell的正常运行
2.4 变量操作
shell中的变量,默认为可读可写类型,如果想要其只可读,如同url一样,需要将其声明为**只读类型变量(**如同const
),使用readonly
命令,如下脚本
#!/bin/bash
Url="http://www.baidu.com"
readonly Url
Url="http://www.csnd.net"
这样的话,这句就会报错,提示/bin/sh: NAME: This variable is read only.
此变量为只读变量
如果想要删除变量,使用unset
命令解除命令赋值,但是unset
不能删除可读变量,如下所示
#!/bin/sh
name="ohuohuo"
Url="http://www.baidu.com"
readonly Url # 设置可读变量
unset name # 可以被删除
unset Url # 不可被删除
echo $name # 不被打印出
echo $Url # 打印出
3.shell字符串
3.1 字符串类型
在shell中字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。
使用单引号
代码语言:javascript复制str='this is a string'
- 1
使用单引号的不足:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
使用双引号
代码语言:javascript复制name="ohouhuoo"
str="please input your "$name""
echo -e $str
输出结果如下图
使用双引号的优势:
- 可以在双引号中使用变量
- 可以在双引号中使用转移字符
由此可见,双引号较单引号而言有更强大的优势
3.2 字符串操作
获取字符串长度:在对变量进行取值时,使用” # “符号对字符串进行取值
代码语言:javascript复制string="abcd"
echo ${#string} # 输出 4
- 1
- 2
提取子字符串:使用字符串的截取命令,用于提取部分字符串
代码语言:javascript复制string="this is a test"
echo ${string:2:6} # 表示从第3个字符开始截取
- 1
- 2
上式输出结果为is is
,如下图
查找字符串:用于查找字符的位置,输出结果为字符在字符串中所占的数据位置,如果查找多个字符,那哪个字母先出现就计算哪个,如下查找it
中i
和t
两个字符,t
先出现,输出为1
string="this is a test"
echo `expr index "$string" it` # 输出 1
- 1
- 2
4.shell数组
在bash下,仅仅支持一维数组,并且没有限定数组的大小,不支持多维数组。类似于 C 语言,数组元素的下标由 0 开始编号(上述字符串也是这样)。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
4.1 定义数组
在 Shell 中,用括号()
来定义表示数组,数组中元素用”空格”符号分割开。定义数组的一般形式为:
# 一般定义
array_name=(value1 value2 value3 value4)
# 多级定义
array_test=(
value1
value2
value3
value4
)
#
array_text[0]=value0
array_text[1]=value1
array_text[3]=value3
...
...
三种定义形式均可
4.2 数组操作
读取数组:和读取变量名相同,使用$
符号,需要加上下标名
valuen=${array_name[n]}
echo ${array_name[@]} # 读取所有
- 1
- 2
获取数组长度:获取数组长度的方法与获取字符串长度的方法相同,如所示
代码语言:javascript复制# 取得数组元素的个数
length=${#array_name[@]} # 从头到尾取
# 或者
length=${#array_name[*]} # 取所有
# 取得数组单个元素的长度
lengthn=${#array_name[n]} # 取特定
5.shell传递参数
在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n
。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……,脚本编写如下,保存为test.sh
echo "传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
执行脚本如下
代码语言:javascript复制chmod x test.sh
./test.sh 1 2 3
- 1
- 2
输出结果如下图,传递参数的过程在赋予权限执行脚本的过程中就已经完成
在使用shell传递参数的时候,常常需要用到以下的几个字符来处理参数
参数处理 | 说明 |
---|---|
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数。 如”$*“用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与∗ 相 同 , 但 是 使 用 时 加 引 号 , 并 在 引 号 中 返 回 每 个 参 数 。 如 ” *相同,但是使用时加引号,并在引号中返回每个参数。 如”∗相同,但是使用时加引号,并在引号中返回每个参数。如”@“用「”」括起来的情况、以”$1″ “2 ” … ” 2″ … “2”…”n” 的形式输出所有参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
举例如下
代码语言:javascript复制echo "传递参数实例!";
echo "第一个参数为:$1";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
结果如图
6.shell运算符
6.1 shell运算符种类
与其他编程语言相同的是,shell同样支持多种运算符:
- 算数运算符
- 关系运算符
- 布尔运算符
- 逻辑运算符
- 字符串运算符
- 文件测试运算符
shell想要使用这些运算符,需要结合其他命令和工具来使用(因为shell中不支持简单的数学运算),如使用算符运算符就需要搭配的常用的工具有两种
- awk
- expr(使用频繁)
运算规则注意点:
- 表达式和运算符之间必须要有空格,例如 3 2 是不对的,必须写成 3 2
- 完整的表达式要被 两个” ` “包含(在 Esc 键下边那个键)
如下实例
代码语言:javascript复制#!/bin/bash
val=`expr 3 2`
echo "两数之和为 : $val"
- 1
- 2
- 3
- 4
执行脚本后,输出结果为
代码语言:javascript复制两数之和为 : 5
- 1
6.2 算数运算符
shell支持的常用的如下表,举例中这里假定变量 a 为 10,变量 b 为 20,
运算符 | 说明 | 举例 |
---|---|---|
| 加法 | expr $a $b 结果为 30。 |
– | 减法 | expr $a - $b 结果为 -10。 |
* | 乘法 | expr $a * $b 结果为 200。 |
/ | 除法 | expr $b / $a 结果为 2。 |
% | 取余 | expr $b % $a 结果为 0。 |
= | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
== | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
需要注意的点:
- 在windows系统中乘号(*)前边必须加反斜杠()才能实现乘法运算;
6.3 关系运算符
shell中的关系运算符和其他编程语言不同,shell中使用特殊的字符表示关系运算符,并且只支持数字,不支持字符串,除非字符串是数字,下表为常用关系运算符,同样指定a为10,b为20
运算符 | 说明 | 举例 |
---|---|---|
-eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
-ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
脚本编写如下
代码语言:javascript复制#!/bin/bash
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
将脚本执行结果如下
代码语言:javascript复制10 -eq 20: a 不等于 b
10 -ne 20: a 不等于 b
- 1
- 2
需要注意的点:
- 运算符和数之间必须要用空格隔开
6.4 布尔运算符
shell中的布尔运算符使用如下表,同样指定a为10,b为20
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
-o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
脚本编写如下
代码语言:javascript复制#!/bin/bash
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a == $b: a 等于 b"
fi
执行脚本,结果如下
代码语言:javascript复制10 != 20 : a 不等于 b
- 1
6.5 逻辑运算符
shell中的逻辑运算符和其他编程语言有类似的地方,如下表。假定变量 a 为 10,变量 b 为 20
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
|| | 逻辑的 OR | [[ $a -lt 100 || $b -gt 100 ]] 返回 true |
编写脚本如下
代码语言:javascript复制#!/bin/bash
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
执行脚本,结果如下
代码语言:javascript复制返回 false
- 1
需要注意的点:
- 这里使用两层的[ ]符号,将两次关系运算的结果保存在条件句中
6.6 字符串运算符
shell中常用的字符串运算符如下表。假定变量 a 为 “abc”,变量 b 为 “efg”
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
-n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n “$a” ] 返回 true。 |
$ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
编写脚本如下
代码语言:javascript复制#!/bin/bash
a="abc"
b="efg"
if [ $a != $b ]
then
echo "$a != $b : a 等于 b"
else
echo "$a != $b: a 不等于 b"
fi
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
执行脚本,结果输出如下
代码语言:javascript复制abc != efg : a 不等于 b
- 1
6.7 文件测试运算符
shell中的文件测试运算符用于检测在类unix系统中,文件的各种属性,如下表
操作符 | 说明 | 举例 |
---|---|---|
-b file | 检测文件是否是块设备文件,如果是,则返回 true。 | [ -b $file ] 返回 false。 |
-c file | 检测文件是否是字符设备文件,如果是,则返回 true。 | [ -c $file ] 返回 false。 |
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-g file | 检测文件是否设置了 SGID 位,如果是,则返回 true。 | [ -g $file ] 返回 false。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 | [ -k $file ] 返回 false。 |
-p file | 检测文件是否是有名管道,如果是,则返回 true。 | [ -p $file ] 返回 false。 |
-u file | 检测文件是否设置了 SUID 位,如果是,则返回 true。 | [ -u $file ] 返回 false。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
编写脚本如下
代码语言:javascript复制#!/bin/bash
file="/var/www/test/test.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
执行脚本,结果输出如下
代码语言:javascript复制文件可读
- 1
7.shell编程中的命令
7.1 echo命令
echo命令在shell中用于字符串的输出,调用的格式:
代码语言:javascript复制echo string
- 1
echo命令还可显示复杂的输出格式
显示普通的字符串
代码语言:javascript复制echo "this is a test"
- 1
显示转义字符
代码语言:javascript复制echo "this is a test"
- 1
显示变量
代码语言:javascript复制name="ohuohuo"
echo "you name is $name"
显示换行
代码语言:javascript复制echo -e "Right!n " # -e 表示开启转义
echo "this is other line"
显示结果定向重定向至文件
代码语言:javascript复制echo "this is a test" > testfile
- 1
显示command命令执行结果
代码语言:javascript复制echo `date`
- 1
echo命令还有其他使用规则,经常使用就可熟练掌握
7.2 printf命令
shell中的printf命令如同C语言中一样,调用格式也大抵相同,只是有一点点不同。与echo命令打印字符串不同的是,printf不会自动调价换行符号,可以手动添加
printf命令的语法:
代码语言:javascript复制printf format-string [arguments...]
- 1
参数说明:
- format-string:格式控制字符串
- arguments:参数列表
举例如下
代码语言:javascript复制$ echo "Hello, Shell" # 输入
Hello, Shell # 输出
$ printf "Hello, Shelln" # 输入
Hello, Shell # 输出
printf命令可以较为强大的使用转义字符,shell中常用的转义字符如下表示所示
序列 | 说明 |
---|---|
a | 警告字符,通常为ASCII的BEL字符 |
b | 后退 |
c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
f | 换页(formfeed) |
n | 换行 |
r | 回车(Carriage return) |
t | 水平制表符 |
v | 垂直制表符 |
一个字面上的反斜杠字符 | |
ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |