shell 编程
一、Shell种类
shell分类 | 说明 |
---|---|
Bourne Shell | 标识为sh,在许多Unix系统中,该Shell是root用户的默认的Shell。 |
Bourne-Again Shell | 标识为bash,是绝大多数Linux发行版的默认的Shell。 |
Korn Shell | 标识为ksh,它完全向上兼容 Bourne Shell 并包含了C Shell 的很多特性。 |
C Shell | 标识为csh,由于其语法类似于C语言,因此称为C Shell |
二、Shell配置文件
Bourne Shell (sh) 的配置文件主要有2个,即用户主目录中的 .bash_profile文件和 /etc/profile文件,/etc/profile 文件是所有的用户共同使用的文件。
每个用户在登录Shell之后,会首先读取和执行/etc/profile文件中的脚本,然后再读取和执行各自主目录中的.profile文件。因此,用户可以将所有用户都需要执行的脚本放在/etc/profile文件中。
Bourne-Again Shell(bash) 的配置文件主要有5个,其中有4个位于用户主目录中,分别为.bash_profile、.bashrc、.bash_logout、.bash_history。1个位于/etc/目录中,名称为bashrc。
.bash_profile: 位于每个用户的主目录中,在该文件中用来保存每个用户自己使用的Shell信息。当用户登录时,该文件将被读取并执行,并且该文件仅被执行一次。默认情况下,.bash_profile文件常常用来设置环境变量,执行用户的.bashrc文件。
.bashrc 文件包含专属于某个用户的bash的相关信息,当用户登录以及每次打开新的bash时,该文件将被读取并执行。
.bash_logout 文件在当前用户每次退出Shell时执行。如果没有特别的要求,该文件的内容通常为空。
三、shell语法
3.1、shell开头
#!
每个脚本的开头都使用 “#!”, 告诉你这个文件的执行需要指定一个解释器。在 “#!” 之后接着是一个路径名,这个路径名指定了一个解释shell的程序,这个程序可以是 shell程序语言或者是任意一个通用程序。这个指定的程序从头开始解释并且执行脚本中的命令。
例如:
#!/bin/sh | 指定/bin/sh为解释器 |
#!/bin/bash | 指定/bin/Bash为解释器,在 Linux 系统中默认是 Bash |
#!/usr/bin/perl | 指定/usr/bin/perl 为解释器 |
在大多数商业发行的 UNIX 上,默认是 Bourne shell,这将让你的脚本可以正常的运行在非 Linux 机器上。
3.2、shell注释
在进行shell编程时,以 “#” 开头的句子表示注释,直到这一行的结束。
3.3、shell脚本运行方法
- ./filename.sh —这种运行方法需要脚本具有可执行权限
- source filename.sh —这种方法不需要文件的可执行权限
- bash filename.sh —使用bash解释器运行
3.4、shell变量
Shell 变量分为 3 种:
- 用户自定义变量
- 预定义变量
- 环境变量
用户自定义变量
这种变量只支持字符串类型,常见有这 3 个前缀:
- unset:删除变量
- readonly:标记只读变量
- export:指定全局变量
预定义变量
预定义变量常用来获取命令行的输入:
$0 :脚本文件名
$1-9 :第 1-9 个命令行参数名
$# :命令行参数个数
$@ :所有命令行参数
$* :所有命令行参数
$? :前一个命令的退出状态,可用于获取函数返回值
$$ :执行的进程 ID
环境变量
环境变量默认就存在,常用的有下面这几个:
- HOME:用户主目录
- PATH:系统环境变量 PATH
- TERM:当前终端
- UID:当前用户 ID
- PWD:当前工作目录,绝对路径
3.5、Shell 字符串
字符串是shell编程中最常用最有用的数据类型(除了数字和字符串,也没啥其它类型好用了),字符串可以用单引号,也可以用双引号,也可以不用引号。单双引号的区别跟PHP类似。
字符串的引用
引用字符串变量时,要在变量前加“$”符号
例如:
mystring="hello"
echo $mystring
mystring前面加$符号,就会被当做一个变量去解析
引号的用法
单引号
str='this is a string'
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
双引号
- 双引号里可以有变量
- 双引号里可以出现转义字符
反引号
如果需要调用命令的输出,或把命令的输出赋予变量,则命令必须使用反引号包含,这条命令才会执行,反引号的作用和 $(命令) 是一样的,但是反引号非常容易和单引号搞混,所以推荐大家使用 $(命令) 的方式引用命令的输出
下面的效果是一样的:
echo $(date)
echo \`date `
3.6、Shell 数组
数组定义
bash支持一维数组,并且没有限定数组的大小。类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。
array_name=(value0 value1 value2 value3)
或者
array_name=(
value0
value1
value2
value3
)
读取数组
数 组 名 [ 下 标 ] 例 如 : v a l u e n = {数组名[下标]} 例如: valuen= 数组名[下标]例如:valuen={array_name[n]}
使用 @ 符号可以获取数组中的所有元素,例如:
echo ${array_name[@]}
获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同,例如:
#取得数组元素的个数
length=${#array_name[@]}
#或者
length=${#array_name[*]}#取得数组单个元素的长度
lengthn=${#array_name[n]}
3.7、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。 |
- 注意:条件表达式要放在方括号之间,并且要有空格,例如: [ a = = a== a==b] 是错误的,必须写成 [ $a == $b ]。
举例:
#!/bin/bash
a=10 b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ] then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi
关系运算
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 1,变量 b 为 2:
运算符 | 说明 | 举例 |
---|---|---|
-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。 |
举例:
#!/bin/bash
a=1
b=2
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
if [ $a -gt $b ]
then
echo "$a > -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ] then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a> -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi
输出:
1 -eq 2: a 不等于 b
1 -ne 2: a 不等于 b
1 -gt 2: a 不大于 b
1 -lt 2: a 小于 b
1 -ge 2: a 小于 b
1 -le 2: a 小于或等于 b
布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 1,变量 b 为 2:
运算符 | 说明 | 举例 |
---|---|---|
! | 非运算,表达式为 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。 |
逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
| | 逻辑的 OR | [[ $a -lt 100 |
字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 “abc”,变量 b 为 “def”:
运算符 | 说明 | 举例 |
---|---|---|
= | 检测两个字符串是否相等,相等返回 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。 |
文件测试运算符
文件测试运算符用于检测 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。 |
举例:
#!/bin/bash
file="/var/runoob/test.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
3.8、Shell 流程控制
if else语法
if condition
then
…
else
… 如果没有这个语句,那么else分支不能有
fi
if else-if else 语法格式:
if condition1
then
…
elif condition2
then
…
else
…
fi
for 循环
当变量值在列表里,for循环即执行一次所有命令,使用变量名获取列表中的当前取值。in列表可以包含替换、字符串和文件名。in列表是可选的,如果不用它,for循环使用命令行的位置参数。
for循环一般格式为:
for var in item1 item2 ... itemN do command1 ... commandN done
举例:
for str in 'This is a string'
do
echo $str
done
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
Sum=0
for i in {1..100}
do
Sum=$(($Sum+$i)) #注意双括号的使用
done
echo "Sum is $Sum"
while 语句
while循环用于循环执行命令,或者从输入文件中读取数据,命令通常为测试条件。
格式:
while condition
do
command
done
举例:
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
i=1
sum=0
while [ $i -le 100 ]
do
let sum=sum+$i
let i++
done
echo $sum
无限循环
无限循环语法格式:
while :
do
command
done
until 循环
until 循环直至条件为 true 时停止,与 while 循环在处理方式上相反。
case语句
Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case语句格式如下:
case value in #value 取值可以为变量或常数。
model1) #每一模式必须以右括号结束
command1
…
commandN
;; #匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
model2)
command1
…
commandN
;;
esac
3.9、Shell 函数
3.10、Shell 文件包含
Shell 包含外部脚本,这样封装一些公用的代码作为一个独立的文件。
Shell 文件包含的语法格式:
. filename
或
source filename
#!/bin/bash
#one.sh
one="this is one in file one.sh"
#!/bin/bash
#two.sh
two="this is two in file two.sh"
#!/bin/bash
#three.sh
. one.sh #方法一
source two.sh #方法二
echo $one
echo $two
运行结果:
this is one in file one.sh
this is two in file two.sh
3.11、echo 指令用法
默认情况下echo输出到标准输出中,使用>指令可重定向输出到文件中。
echo向文件中输出内容的基本方法是使用IO重定向指令——“>”,本文总结如何使用echo命令向文件中写入内容,例如使用echo指令覆盖文件内容,使用echo指令向文件追加内容,使用echo指令往文件中追加制表符。
覆盖文件内容
echo "hello" > test.txt
追加文件内容
echo "hello" > test.txt
echo "hi" >> test.txt
输出:
hello hi