1. shell作为应用程序
交互式地解释、执行用户输入的命令,将用户的操作翻译成机器可以识别的语言,完成相应功能称之为shell命令解析器
shell是用户和Linux内核之间的接口程序
shell本质是对内核起到保护作用,只有shell能够识别的命令才能够直接操作内核来控制硬件
2. shell作为一门语言
它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支完成类似于windows下批处理操作,简化我们对系统的管理与应用程序的部署称之为shell脚本.
shell脚本是shell命令的有序集合
shell脚本是一种脚本语言,我们只需使用任意文本编辑器,按照语法编写相应程序,增加可执行权限,即可在安装shell命令解释器的环境下执行
3. shell脚本主要作用
帮助开发人员或系统管理员将复杂而又反复的操作放在一个文件中,通过简单的一步执行操作完成相应任务,从而解放他们的负担
4. shell脚本的执行
shell脚本的代码编写流程
第一步:指定shell脚本文件,一般以.sh作为后缀名,也可以不加,例如:test.sh
第二步:编写代码
#!/bin/bash
# #!用于指定当前脚本文件的shell解释器的类型,如果不写,则用默认的shel l
#shell脚本是shell命令的有序集合,代码的构成就是命令
ls
pwd
echo "hello world"
第三步:修改文件权限
chmod +x test.sh
第四步:执行脚本文件
./test.sh
或者 bash test.sh (这种方式不需要修改文件权限)
执行结果
5. 变量
5.1 自定义变量
代码展示:
#!/bin/bash
#定义变量 4 #shell脚本中没有数据类型可言,所以定义变量时不需要加数据类型 5 #shell脚本中,赋值操作时不能在等号两边加空格
#NUM = 100 #错误
NUM=100
#引用变量 10 # $变量名 取一个变量的值
i=$NUM
#显示变量
echo $NUM
echo $i
#清除变量
unset NUM
echo "*************"
echo $NUM
#使用read从终端读取数据保存在变量中
read str
echo "str = $str"
#使用readonly创建一个只读的变量
readonly n=999
echo "n = $n"
#指定变量初始化后不能再次修改变量的值,只能使用
#n=666
#echo "n = $n"
5.2 环境变量
shell在开始执行时就已经定义了一些和系统的工作环境有关的变量,我们在shell中可以直接使用$name引用
定义:一般在~/.bashrc或/etc/profile文件中(系统自动调用的脚本)使用export设置,允许用户后来更改
设置环境变量:
方法1:临时设置在终端执行命令
MYVAL=999
export MYVAL
方法2:永久设置
需要在配置文件(~/.bashrc或/etc/profile)中进行设置即可,设置完毕后需要通过 source命令配置文件立即生效
使用环境变量,一般环境变量类似c语言中的全局变量,可以再shell脚本文件中任意使用
代码展示:
#!/bin/bash
echo "You are welcome to use bash"
echo "Current work dirctory is $PWD"
echo "the host name is $HOSTNAME"
echo "your home dir $HOME"
echo "Your shell is $SHELL"
echo "user env val is $MYVAL1"
执行结果:
5.3 预设变量
- $#:传给shell脚本参数的数量
- $*:传给shell脚本参数的内容
- $1、$2、$3、...、$9:运行脚本时传递给其的参数,用空格隔开
- $?:命令执行后返回的状态
- "$?"用于检查上一个命令执行是否正确(在Linux中,命令退出状态为0表示该命令正确执行,任何非0值表示命令出错)。
- $0:当前执行的进程名
- $$:当前进程的进程号
- "$$"变量 常见的用途是用作临时文件的名字以保证临时文件不会重复
代码展示:
#! /bin/bash
#位置变量$0 ‐ $9 保存从终端输入的每一个参数
echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$5 = $5"
echo "\$6 = $6"
echo "\$7 = $7"
echo "\$8 = $8"
echo "\$9 = $9"
#如果超过9,需要加大括号
echo "\$10 = ${10}"
#$#:保存命令行传入的参数的个数,不包括$0
echo "\$# = $#"
#$@或者$*:保存所有的命令行传入的参数,但是不包括$0
echo "\$@ = $@"
echo "\$* = $*"
#$$:获取当前进程的进程号
echo "\$$ = $$"
//read NUM
# $? 返回上一个命令执行的结果,如果执行成功,则$?的值为0,执行失败,则为非0
ls
echo "\$? = $?"
ls asdfasdf
echo "\$? = $?"
执行结果
6. 脚本变量的特殊用法
6.1 " "(双引号):包含的变量会被解释
6.2 ' '(单引号):包含的变量会当做字符串解释
6.3 ` `(数字键1左面的反引号):反引号中的内容作为系统命令,并执行其内容,可以替换输出为一个变量
例如:$ echo "today is `date` " today is 2012年07月29日星期日 12:55:21 CST
6.4 \ 转义字符:同c语言 \n \t \r \a等 echo命令需加-e转义
6.5 (命令序列):由子shell来完成,不影响当前shell中的变量
6.6 { 命令序列 }:在当前shell中执行,会影响当前变量
代码展示:
#!/bin/bash
name="zhangsan"
#双引号里面的特殊字符,会使用其特殊含义
string1="good moring $name"
#单引号里面的特殊字符,都会失去特殊含义
string2='good moring $name'
echo $string1
echo $string2
#反引号:获取一个shell命令的输出结果,一般对有输出结果的命令经常去使用,也可以使用$()与反引号等价
echo "today is date"
echo "today is `date`"
echo 'today is `date`' 16 echo "My dir is $(ls)"
#转义字符:使用时,需要在echo后面加上‐e选项
echo "**************"
echo "this \n is\ta\ntest"
echo ‐e "this \n is\ta\ntest"
echo "**************"
num=100
#由子shell来完成,不影响当前shell中的变量
( num=999;echo "1 $num" )
echo 1:$num
#在当前shell中执行,会影响当前变量
{ num=666; echo "2 $num"; }
echo 2:$num
执行结果:
7. 条件测试语句
在写shell脚本时,经常遇到的问题就是判断字符串是否相等,可能还要检查文件状态或进行数字测试,只有这些测试完成才能做下一步动作
test命令:用于测试字符串、文件状态和数字
test 命令有两种格式:test condition 或 [ condition ]
注意:使用方括号时,要注意在条件两边加上空格
7.1 文件测试
按照文件类型
- -e 文件名 文件是否存在
- -s 文件名 是否为非空
- -b 文件名 块设备文件
- -c 文件名 字符设备文件
- -d 文件名 目录文件
- -f 文件名 普通文件
- -L 文件名 软链接文件
- -S 文件名 套接字文件
- -p 文件名 管道文件
7.2 按照文件权限
- -r 文件名 可读
- -w 文件名 可写
- -x 文件名 可执行
代码展示:
#! /bin/bash
echo "please input a filename >>> "
read FILE
test ‐e $FILE
echo "存在?$?"
test ‐s $FILE
echo "非空?$?"
[ ‐r $FILE ]
echo "可读?$?"
[ ‐w $FILE ]
echo "可写?$?"
[ ‐x $FILE ]
echo "可执行?$?"
test ‐b $FILE
echo "块设备文件?$?"
test ‐c $FILE
echo "字符设备文件?$?"
test ‐d $FILE
echo "目录文件?$?"
test ‐f $FILE
echo "普通文件?$?"
test ‐L $FILE
echo "软链接文件?$?"
test ‐S $FILE
echo "套接字文件?$?"
test ‐p $FILE
echo "管道文件?$?"
执行结果
8. 两个文件之间的比较
文件1 -nt 文件2 文件1的修改时间是否比文件2新
文件1 -ot 文件2 文件1的修改时间是否比文件2旧
文件1 -ef 文件2 两个文件的inode节点号是否一样,用于判断是否是硬链接
9. 字符串测试
s1 = s2 测试两个字符串的内容是否完全一样
s1 != s2 测试两个字符串的内容是否有差异
-z s1 测试s1 字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0
代码展示:
#! /bin/bash
test "hello" = "hello"
echo "相等?$?"
test "hello" = "hella"
echo "相等?$?"
test "hello" != "hello"
echo "不相等?$?"
test "hello" != "hella"
echo "不相等?$?"
test ‐z "hello"
echo "长度是否为0?$?"
test ‐n "hello"
echo "长度是否不为0?$?"
执行结果:
10. 数字测试
- a -eq b 测试a 与b 是否相等
- a -ne b 测试a 与b 是否不相等
- a -gt b 测试a 是否大于b
- a -ge b 测试a 是否大于等于b
- a -lt b 测试a 是否小于b
- a -le b 测试a 是否小于等于b
英文单词 | shell比较符 | |
相等 | equal | -eq |
不相等 | not equal | -ne |
大于 | greater than | -gt |
大于等于 | greater equal | -ge |
小于等于 | less equal | -le |
小于 | less than | -lt |
代码展示:
#! /bin/bash
echo "please input two numbers >>> "
read NUM1 NUM2
test $NUM1 ‐eq $NUM2
echo "相等?$?"
test $NUM1 ‐ne $NUM2
echo "不相等?$?"
test $NUM1 ‐gt $NUM2
echo "大于?$?"
test $NUM1 ‐ge $NUM2 16 echo "大于等于?$?"
test $NUM1 ‐lt $NUM2
echo "小于?$?"
test $NUM1 ‐le $NUM2
echo "小于等于?$?"
执行结果:
11. 复合测试
11.1. 命令执行测试
1. &&:
command1 && command2
&& 左边命令(command1)执行成功(即返回0),shell才执行&&右边的命令(command2)
2. ||:
command1 || command2
|| 左边的命令(command1)未执行成功(即返回非0),shell才执行||右边的命令(command2)
11.2. 多重条件测试
-a | (and)两状况同时成立 test -r file -a - x file file同时具有r与x权利时,才为true |
-o | (or)两状况任何一个成立 test -r file -a - x file file具有r或x权利时,传回true |
! | 相反状态 test ! -x file 当file不具有x权利时,传回true |
代码展示:
#! /bin/bash
num=100
#判断 0 <= num <= 200
#test $num ‐ge 0 && test $num ‐le 200
test $num ‐ge 0 ‐a $num ‐le 200
echo "$?"
#判断 num <= 0 或者 num >= 200
test $num ‐le 0 || test $num ‐ge 200
echo "$?"
file="file.txt"
#判断文件是否不是普通文件
test ! ‐f $file
echo "$?"
#判断文件是否存在并且是否是目录文件
test ‐e $file && test ‐d $file
echo "$?"
执行结果:
12. if控制语句
12.1 if语句格式一
if [ 条件1 ]; then
执行第一段程序
else
执行第二段程序
fi
12.2 if格式二
if [ 条件1 ]; then
执行第一段程序
elif [ 条件2 ];then
执行第二段程序
else
执行第三段程序
fi
代码展示:
#! /bin/bash
echo "please input a number >>> "
read NUM
#注意:赋值时,等号两边不能加空格 7 # []里面存放表达式时必须加空格
#一般形式
if [ $NUM ‐gt 50 ];then
echo "NUM > 50"
fi
if [ $NUM ‐gt 50 ];then
echo "NUM > 50"
else
echo "NUM <= 50"
fi
echo "***********************"
#阶梯形式
if [ $NUM ‐gt 50 ];then
echo "NUM > 50"
elif [ $NUM ‐lt 50 ];then
echo "NUM < 50"
else
echo "NUM = 50"
fi
echo "***********************"
#嵌套形式
if [ $NUM ‐gt 50 ];then
echo "NUM > 50"
elif [ $NUM ‐eq 50 ];then
echo "NUM = 50"
else
echo "NUM < 50"
if [ $NUM ‐gt 30 ];then
echo "NUM > 30"
else
echo "NUM <= 30"
fi
fi
执行结果:
13. case控制语句
13.1 语句格式
case $变量名称 in
“第一个变量内容”)
程序段一
;;
“第二个变量内容”)
程序段二
;;
*)
其它程序段
exit 1
esac
代码展示:
#!/bin/bash
echo "This script will print your choice"
case "$1" in
"one")
echo "your choice is one"
;;
"two")
echo "your choice is two"
;;
"three")
echo "Your choice is three"
;;
*)
echo "Error Please try again!"
;;
esac
echo "hello world"
执行结果:
14. declare
declare:是bash的一个内建命令,可以用来声明shell变量、设置变量的属性;
declare 也可以写作 typeset ;
declare -i s:代表强制把 s 变量当做 int 类型参数运算。
15. for控制语句
15.1 形式一
for (( 初始值; 限制值; 执行步阶 ))
do
程序段
done
代码展示:
#!/bin/bash
#声明sum变量是一个整数变量,准备保存整数
declare ‐i sum
for (( i=1; i<=100; i++ ))
do
sum=sum+i
done
echo "The result is $sum"
执行结果:
15.2 形式二
for var in con1 con2 con3 ...
do
程序段
done
第一次循环时,$var的内容为con1
第二次循环时,$var的内容为con2
第三次循环时,$var的内容为con3
...
当in后面所有的值都赋值完毕并执行命令后,循环结束
代码展示:
#!/bin/bash
#注意:for循环后的变量之前不能加$
for i in 1 2 3 4 5 6 7 8 9
do
echo $i
done
执行结果:
代码展示:
#!/bin/bash
for name in `ls`
do
if [ ‐f $name ];then
echo "$name is file"
elif [ ‐d $name ];then
echo "$name is directory"
else
echo "^_^"
fi
done
执行结果:
16. while控制语句
while [ condition ]
do
程序段
done
当condition成立的时候进入while循环,直到condition不成立时才退出循环。
代码展示:
#!/bin/bash
declare ‐i i
declare ‐i s
while [ "$i" != "101" ]
do
s+=i;
i=i+1;
done
echo "The count is $s"
执行结果:
17. until控制语句
until [ condition ]
do
程序段
done
这种方式与while恰恰相反,当condition成立的时候退出循环,否则继续循环。
代码展示:
#!/bin/bash
declare ‐i i
declare ‐i s
#until循环,是循环条件不成立,执行命令体,如果条件为真,则循环结束
until [ "$i" = "101" ]
do
s+=i;
i=i+1;
done
echo "The count is $s"
执行结果:
18. break、continue
18.1 break
break命令允许跳出循环。
break 通常在进行一些处理后退出循环或case 语句
18.2 continue
continue 命令类似于break 命令
只有一点重要差别,它不会跳出循环,只是跳过这个循环步骤
代码展示:
#! /bin/bash
for ((num=1; num<=10; num++))
do
if [ $num ‐eq 5 ]
then
#break退出整个循环
break
fi
echo "num = $num"
done
执行结果:
代码展示:
#! /bin/bash
for ((num=1; num<=10; num++))
do
if [ $num ‐eq 5 ]
then
#continue退出本层循环,当执行到continue的位置时,循环下方的代码不在执行
#但是接着下个循环继续执行
continue
fi
echo "num = $num"
done
执行结果:
19. shell函数
19.1 shell函数概念
有些脚本段间互相重复,如果能只写一次代码块而在任何地方都能引用那就提高了代码的可重用性。shell允许将一组命令集或语句形成一个可用块,这些块称为shell函数。
19.2 函数的定义和调用
格式一:
函数名()
{
命令 ...
}
格式二:
function 函数名()
{
命令 ...
}
19.3 调用函数的格式
函数名 param1 param2……
代码展示:
#! /bin/bash
#定义一个函数
#由于shell中没有主函数一说,所以一般函数都需要定义在整个代码的最上边,下方对其进行调用
myfun()
{
echo "hello world"
echo "nihao beijing"
}
#函数的调用
myfun
myfun
myfun
执行结果:
19.4 函数传参
使用参数同在一般脚本中使用特殊变量 $1,$2 ...$9一样
代码展示:
#! /bin/bash
myadd()
{
#shell函数传参
#shell函数中想要传参,不能在函数名后的括号里面定义
#而是使用$1 $2 ...保存外部传入的值
A=$1
B=$2
SUM=`expr $A + $B`
echo "$A + $B = $SUM"
}
#带参数的shell函数的调用
myadd 100 200
num1=666
num2=777
myadd $num1 $num2
执行结果:
19.5 函数返回值
函数可以使用return,提前结束并带回返回值;
return 从函数中返回,用最后状态命令决定返回值。
return 0 无错误返回
return 1 有错误返回
代码展示:
#! /bin/bash
myadd()
{
A=$1
B=$2
SUM=`expr $A + $B`
return $SUM
}
myadd 10 20
#函数的返回值一般通过$?可以获取到,但是$?获取到的最大值是255,如果超过这个值,会出错
echo "$?"
myadd 100 200
#echo "$?"
#在shell中,除了()中定义的变量,只要不做任何修饰,
#都可以认为是全局变量,可以再任意一个位置调用
echo "SUM = $SUM"
执行结果: