Linux shell脚本编程
Linux shell脚本编程:
守护进程,服务进程:启动?开机时自动启动:
交互式进程:shell应用程序
广义:GUI,CLI
GUI:
CLI:
词法分析:命令,选项,参数
内建命令:
外部命令:PATH
fork()创建为一个进程:
把要运行的一系列命令,写在文件中:
脚本或程序源文件:文本文件
两种方式:
编译执行:预处理---->编译---->汇编---->链接:事先完成,结果:二进制程序文件
C,C++
解释执行:由解释器全程参与运行过程,每次读取一行,运行一行;
Python:程序库
程序控制结构:调用编程库完成编程编写;
库文件:功能模块,在编程中可调用;通过其API:应用编程接口;
Bash:程序
程序控制结构,调用机器上命令程序文件进行编程编写;
外部命令:各应用程序提供;
程序:指令+数据
算法+数据结构
过程式编程:以指令为中心,设计算法,数据服务于算法;
对象式编程:以数据为中心,设计数据结构(类),程序服务于数据结构;
bash过程式编程:
顺序执行:逐个执行
选择执行:只执行其中一个分支
循坏执行:一段代码要执行0,1或多遍
编程元素:变量、流程、函数
变量:可变化的量,命名内存空间
bash环境:
本地变量:当前shell进程;
环境变量:当前shell进程及其子进程;
局部变量:某个函数执行过程;
位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;
特殊变量:$?,$*,$@,$#,$$
变量类型:
数值,字符:
数值:
整数
浮点数
字符:
ASCII
120:
字符:1, 2 , 0
数值:120 --->
变量类型的作用:
存储空间
运算格式
语言对变量类型的支持力度:
强类型:
弱类型:变量类型不严格区分;
默认存储机制:bash为字符
bash的变量使用特点:弱类型、无需事先说明;
本地变量:
name=value
name:变量名
=:赋值符号
value:值
变量名:只能包含数字、字母和下划线:且不能以数字开头;
引用变量:${name},name
例:
[root@localhost ~]# animal="panao"
[root@localhost ~]# echo ${animal}
panao
引用:
弱引用:"",其内部的变量引用会替换为变量值;
强引用:'',其内部的变量引用会保持原有字符;
命令引用:`COMMAND`,$(COMMAND),引用命令的执行结果;
声明为整型:
declare -i name[=value]
let name=value
生命周期:
创建
销毁:
自动销毁:shell进程终止;
手动销毁:unset name
例:
[root@localhost ~]# unset animal
环境变量:
被"导出"的本地变量
export name[=value]
declare -x name[=value]
查看所有环境变量:env,printenv,export
销毁:
unset name
脚本:文本文件
运行脚本:事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,而后有bash进程负责解析并运行此逻辑;
启动脚本:
(1) #bash /PATH/TO/SCRIPT_FILE
(2)一个执行权限,
# ./PATH/TO/SCRIPT_FILE
shebang:
#!/bin/bash
第一行:顶格给出shebang
注释行:#
bash的常用选项:
-n:检查脚本中的语法错误;
-x:调试执行脚本;
命令的状态结果:
bash进程用于追踪执行的命令成功与否的状态;
0:成功
1-222:失败
特殊变量:
$?:上一条命令的执行状态结果;
例:
[root@localhost bin]# echo $?
0 // 0表示成功
布尔型:
"真":成功
"假":失败
自定义脚本的状态结果:
exit[n]
注意:脚本中任何位置执行了exit命令即会终止当前shell进程;
条件测试:
界定程序执行环境:
(1)根据运行的命令的状态结果;
(2)测试表达式
test EXPRESSION
[ EXPRESSION ] //括号两边必须有空格
[[ EXPRESSION ]] //括号两边必须有空格
整数测试:隐含着做数值大小比较,所以不要给变量引用加引用;
$A -gt $B:是否大于:是则为"真",否则为"假";
$A -ge $B:是否大于等于;
$A -lt $B:是否小于;
$A -le $B:是否小于等于;
$A -eq $B:是否等于;
$A -ne $B:是否不等于;
字符串测试:ASCII数值越大,字符比较时其值越大
"$A" > "$B":是否大于;
"$A" < "$B":是否小于;
"$A" == "$B":是否等于;
"$A" != "$B":是否不等于;
-z "$A":是否为空;空则为"真",否则为"假"
-n "$A":是否不空;不空则为"真",空则为"假"
注意:应该使用[[ EXPRESSION ]]
文件测试:测试文件的存在性以及属性;
-e $file:是否存在,存在则为"真",否则为"假"
-a $file:同上
-f $file:文件是否存在且为普通文件;
-d $file:文件是否存在且为目录;
-h $file:是否存在且为符号链接文件;
-L $file:同上;
-b $file:是否存在且为块设备文件;
-c $file:是否存在且为字符设备文件;
-S $file:是否存在且为套接字文件;
-p $file:是否存在且为管道文件;
-r $file:当前用户对文件是否拥有读权限;
-w $file:当前用户对文件是否拥有写权限;
-x $file:当前用户对文件是否拥有执行权限;
-u $file:文件是否拥有SUID权限;
-g $file:文件是否拥有SGID权限;
-k $file:文件是否拥有sticky权限;
-O $file:当前用户是否为指定文件的属主;
-G $file:当前用户是否为指定文件的属组;
双目操作符:
$file1 -nt $file2:file1是否新于file2,file1的最近一次的修改时间是否晚于file2的;
$file1 -ot $file2:file1是否旧于file2,file1的最近一次的修改时间是否早于file2的;
$file1 -ef $file2:file1与file2是否指向了同一个inode:测试二者是否为同一个文件的硬链接;
特殊设备:
/dev/null:空,bit buckets,吞下所有数据,并直接丢弃;
/dev/zero:突出一堆0:
bash之条件判断(选择执行):
if/then,case
if CONDITTION;then
if-true-分支
fi
if CONDITTION;then
if-true-分支
else
if-false-分支
!CONDITTION:取反
练习:写一个脚本
如果其路径不存在,则将其创建为目录,否则显示其存在,并显示内容类型;
#!/bin/bash
#
filename="/tmp/x/y/z/testdir"
if [ -e $filename ];then
echo "$filename exists."
file $filename
else
mkdir -p $filename
fi
~
~
脚本参数(位置参数变量):
./script.sh /etc/fstab /etc/grub2.cfg
$0 $1 $2
位置参数变量:$1,$2,....
${10}
特殊变量:
$?:命令的状态结果;
$#:传递给脚本或函数的参数个数;
$*和$@:引用传递给脚本或函数的参数列表;
shift:[n]:轮替
与用户交互:
read命令:
read [option] VAR...
-p "PROMPT"
-t timeout
示例:
#!/bin/bash
#
read -p "Plz enter a username: " -t 5 username
if [ -z "$username" ]; then
username="myuser"
fi
if id $username &> /dev/null; then
echo "$username exists."
else
useradd $username
fi
命令引用:
`COMMAND`,$(COMMAND)
引用命令的执行结果:
(1)ls `which cat`
(2)lines=$(wc -l /etc/fstab | cut -d '' -f1)
#!/bin/bash
#
if [ -f $1 ]; then
lines=$(wc -l $1 | cut -d' ' -f1)
echo "$1 has $lines lines."
else
echo "$1 not exists or not a file."
fi
练习:写一个脚本,完成如下功能:
判断给定的两个数值,孰大孰小;
给定数值的方法:脚本参数,命令交互;
代码如下:
1 #!/bin/bash
2 #
3 read -p "Plz enter two integer: " -t 10 num1 num2
4
5 if [ -z "$num1" ];then
6 echo "Plz give two integers."
7 exit 1
8 fi
9
10 if [ -z "$num2" ];then
11 echo "Plz give two integers."
12 exit 1
13 fi
14
15 if [$num1 -ge $num2 ];then
16 echo "Max: $num1,Min;$num2."
17 else
18 echo "Max:$num2,Min:$num1."
19 fi
循环语句:
for,while,until
循环:将循坏体代码执行0、1或多次;
进入条件:进入循环的条件;
退出条件:循环终止的条件;
for VARIABLE in LIST;do
循环体
done
LIST:是由一个或多个空格分隔开的字符串组成;
把列表的每个字符串逐个赋值给VARIABLE表示的变量;
for username in user1 user2 user3;do
循环体
done
进入条件:列表非空
退出条件:列表遍历结束;
添加5个用户:
#!/bin/bash
#
for username in user1 user2 user3 user4 user5; do
if id $username &> /dev/null; then
echo "$username exists."
else
useradd $username
echo "Add user $username finished."
fi
done
LIST的生成方法:
(1)整数列表
(a){start..end}
(b)$(seq start [[step]end])
(2)直接给出
(3)glob
(4)根据命令生成
示例:数值列表
#!/bin/bash
#
for i in {1..10}; do
if id user$i &> /dev/null; then
echo "user$i exists."
else
useradd user$i
echo "Add user user$i finished."
fi
done
示例:glob
#!/bin/bash
#
for filename in /var/log/*; do
file $filename
done
示例:命令生成列表
#!/bin/bash
#
for username in $(cut -d: -f1 /etc/passwd); do
echo "$username primary group: $(id -n -g $username)."
done
~
算术运算:
+,-,*,%,**
sum=$a+$b
(1)$[$A+$B]
(2)$(($A+$B))
(3)let VARIABLE=$A+$B
(4)VARIABLE$(expr $A + $B)
示例:
[root@localhost bin]# a=6
[root@localhost bin]# b=7
[root@localhost bin]# sum=$a+$b
[root@localhost bin]# echo $a+$b
6+7
[root@localhost bin]# echo $[$a+$b]
13
[root@localhost bin]# let $a+$b
[root@localhost bin]# let sum=$a+$b
[root@localhost bin]# echo $sum
13
[root@localhost bin]# expr $a + $b
13
示例:求100以内正整数之和;
#!/bin/bash
#
declare -i sum=0
for i in {1..100}; do
sum=$[$sum+$i]
done
echo $sum
练习:求100以内所有偶数之和;
使用至少三种方法实现;