一.程序简介
程序
程序:算法+数据结构 数据结构:数据在计算机中的类型和组织方式 算法:处理数据的方式 面向过程:以指令为中心,数据服务于指令 面向对象:以数据为中心,指令服务于数据 计算机:二进制执行
高级编程语言:
编译:高级语言->编译器->机器代码->执行 解释:高级语言->执行->解释器->机器代码 shell
三大逻辑
顺序、循环、选择
二.shell脚本
1.格式
格式要求:首行shebang机制 #!/bin/bash 指定shell类型 # 注释 程序名,作用说明,版本信息,作者信息 bash -n 检查语法错误 bash -x 跟踪调试脚本的执行过程
2.变量
变量的类型:
字符、整型 强类型 弱类型 不需要声明变量类型 不支持浮点型 都以字符串的形式存储
命名规则:
不能是内部命令、系统关键字 字母、数字、下划线 不能以数字开头
定义变量
a=linux a=‘linux‘ a="linux" 上面三个都是把linux这个字符串赋值给变量a,如果赋值的一方当中没有空格,则不用引号,如果有空格则必须用引号。
使用变量
echo $a echo ${a} 调用变量a,在变量前面加上$即可,变量用{}括起来是个良好的习惯 已经定义的变量也可以重新赋值 a=centos unset a 删除变量 readonly a 只读变量,不能修改
单双引号的区别
单引号 ‘‘ 强引用,单引号里所有内容都作为字符输出 双引号 "" 若引用,双引号里有变量的时候,会读取变量值输出,而不是直接输出
把命令执行结果赋值给变量
a=`cat /etc/fstab` 使用反向单引号 a=$(cat /etc/fstab) 使用$() 反向单引号容易和单引号混淆,因此推荐使用$()
局部变量和全局变量
局部变量:生效范围是当前shell进程 全局变量:生效范围是当前shell及其子进程 export a 声明全局变量 set 显示变量,自定义和系统自带的 export 或 declare 显示环境变量 echo $PPID 显示父进程编号 pstree -p 显示进程信息 source 运行的脚本在本bash环境下,会修改某些当前bash下的环境。 bash 运行脚本时会新开一个bash,为当前bash的子进程,不会影响当前环境 SHLVL 变量,shell 的嵌套深度 echo $_ 上一个命令的最后一个字符串 unset name 删除变量,除了只读变量 readonly 查看只读变量 declare -r (umask=0022;touch a) () 不开启子进程 {} 开启子进程
位置变量
$$ 当前shell的ID $1 第一个参数 $* 所有参数,认为所有参数是一个整体 [email protected] 所有参数,认为所有参数是独立的个体 $# 参数数量 $0 当前脚本的文件名 10以上的加{} shift n 变量按顺序往前移动n个变量 set -- 清除变量
退出状态
$? 变量保存最近(前一个)的命令退出状态 0 代表成功,1-255 代表失败 脚本里指定返回值 exit 10
2.运算
bash支持算术运算、关系运算、布尔运算、字符串运算和文件测试运算等
算术运算
expr 2 + 4 echo `expr 2 + 4 a=`expr 2 + 4` c=`expr $a + $b` expr是一款表达式计算工具,数值和运算符之间必须有空格,调用整个表达式的时候记得加`` let sum=x+y $[x+y] $((x+y)) expr 2 + 3 expr是一个命令 declare -i n=10 指定n是个整数,声明变量 -= += -- ++
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | `expr $a + $b |
- | 减法 | `expr $a - $b |
* | 乘法 | `expr $a \* $b |
/ | 除法 | `expr $a / $b |
% | 取余 | `expr $a % $b |
= | 赋值 | a=$b |
== | 比较两个数字是否相等 | [ $a == $b ] |
!= | 比较两个数是否不等 | [ $a != $b ] |
表达式和[ ]之间需要有空格
逻辑运算
true 1 ;false 0; 与 & 有0即0 或 | 有1即1 非 ! 取反 短路与 && 前一个为假则不再判断第二个 短路或 || 前一个为真则不再判断第二个 异或 ^ 相同为假,相异为真 同或 相同为真,相异为假
测试命令:
test 不支持正则表达式,没值就为假,变量加“” [[]] 支持正则表达式 [] 有值就为真 [] 和变量之间要加空格
几种括号的用法
(; ; ) 几个命令一起执行,开启子shell {; ; } 几个命令一起执行,不开启子shell,前后空格,最后一个加;号 [] 逻辑判断,不支持正则表达式 [[]] 逻辑判断,支持正则表达式,一般用[] =~ 匹配,字符串不要加"",支持正则表达式 != 不等 == 相等,字符串不要加"",支持通配符
关系符运算
数值测试,不支持字符
运算符 | 说明 | 全称 |
---|---|---|
-gt | 是否大于 | greater than |
-ge | 是否大于等于 | greater than equal |
-eq | 是否等于 | equal |
-ne | 是否不等于 | no equal |
-lt | 是否小于 | less than |
-le | 是否小于等于 | less equal |
字符串测试
= 是否等于 > ascii码是否大于 < 是否小于 != 是否不等于 =~ 左侧字符串是否能够被右侧的pattern匹配,一般用于[[]]中 -z "string" 字符串是否为空,空为真,非空为假 -n "string" 字符串是否不空,不空为真,空位假
文件测试
-a / -e file :文件存在性测试,存在未真,否则为假 -b 是否存在且为块设备文件 -c 是否存在且为字符设备文件 -d 是否存在且为目录文件 -f 是否存在且为普通文件 -h / -L :存在且为链接文件 -p 是否存在且为命名管道文件 -S 是否存在且为套接字文件
权限测试
-r 是否存在且可读 -w 是否存在且可写 -x 是否存在且可执行 -u 是否存在且拥有suid权限 -g 是否存在且拥有sgid权限 -k 是否存在且拥有sticky权限
-s 是否存在且为非空 -t 文件描述符是否在某终端打开 -N 文件自从上一次被读取之后是否被修改 -O 当前有效用户是否为文件时属主 -G 当前用户是否为文件属组
双目测试
file1 -ef file2:1是否是2的硬链接 file1 -nt file2:1是否新于file2 file1 -ot file2:1是否旧于file2 -a 并且 -o 或者 ! 非
3.字符串
单引号
str=‘this is a string‘ 单引号里的任何字符都会原样输出,单引号里的变量是无效的 单引号字符串中不能出现单引号,对单引号转义后也不行
双引号
str="you name is $name" 双引号里可以有变量 双引号里可以出现转义字符
拼接字符串
firstname="zhang" lastname="hw" echo $firstname $lastname 输出:zhanghw
获取字符串长度
str="abcd" echo ${#str} 输出:4
提取子字符串
str="daxiong is the best girl" echo ${str:1:4} 1:4 起始字符到终止字符,由0开始
查找子字符串
str="daxiong is the best girl" echo `expr index "$str" is`
4.数组
只支持一维数组,没有限定数组大小。数组元素下表从0开始,下表可以是整数或算术表达式,其值应大于或等于0
定义
用括号来定义数组,各个元素间用空格分开,如下: array_name=(value0 value1 value2) 单独定义 array_name[0]=value0 array_name[1]=value1
引用
${array_name[index]} a=${array_name[0]} ${array_name[@}} ${array_name[*]} @或* 可以获取数组中的所有元素
获取数组的长度
a=${#array_name[@]} 取得数组元素的个数 @或*都可以 a=${#array_name[n]} 取得下标为n的元素的长度
5.shell printf
printf命令用于格式化输出,printf由POSIX标准所定义,移植性比echo好
printf "hello\n" 输出字符串,printf不自带换行,需要在字符串最后添加\n printf format-string [arguments] format-string为双引号 $ printf "%d %s\n" 1 "abc" 1 ab 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用 $ printf %s abc def abcdef $ printf "%s\n" abc def abc def $ printf "%s %s %s\n" a b c d e f g h i j a b c d e f g h i j 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替 $ printf "%s and %d \n" and 0
6.if else 语句
- if...fi
- if...else...fi
- if...elif...else...fi
最后必须以fi结尾来闭合
if 语句的用法
if [ expression ] then Statement(s) to be executed if expression is true fi 如果expression返回ture,then后面的语句将会被执行;如果返回false则跳出循环
if..else...fi 语句的用法
if [ expression ] then Statement(s) to be executed if expression is true else Statement(s) to be executed if expression is not true fi 如果expression返回true则执行then后面的语句,否则执行else后面的语句
if...elif...fi 语句的用法
if [ expression 1 ] then Statement(s) to be executed if expression 1 is true elif [ expression 2 ] then Statement(s) to be executed if expression 2 is true else Statement(s) to be executed if no expression is true fi 哪一个expression 的值为true,就执行那个expression后面的语句,如果都为false则执行else后面的语句
7.for循环
for varibale in 列表 do command1 command2 ... conmmandN done 列表是一组数值(数值、字符串等)组成的序列,每个值通过空格分格。每循环一次,就将列表中的下一个值赋给变量 in 列表是可选的,如果不用它,for循环使用命令行的位置参数 seq 列表的产生 wait
8.while循环
-
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件
while command
do
Statement(s) to be executed if command is true
done
: 代表true的意思
9.until循环
-
直到型循环,当执行结果为true时才跳出循环。
until command
do
Statement(s) to be executed until command is true
done
10.continue
跳过本次循环 > break [N] 直接结束第N层的本轮循环,而直接进入下一轮判断,最内层为第1层,默认值为1 while command1 do if command2 then continue fi done
11.break
跳出整个循环 break [N] 提前结束第N层循环,最内层为第一层 while command1 do if command2 then break fi done
12.shift
shift [n]
将参量列表list左移指定次数,缺省为左移一次。列表list一旦被移动,最左端的那个参数就从列表中删除。
#!/bin/bash #step through all the positional parameters until [ -z "$1" ] do echo "$1" shift done echo
13.select
select variable in list do 循环体命令 done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在
标准错误上,并显示 PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要记住用 break 命令退出循环,或用
exit 命令终止脚本。也可以按 ctrl+c 退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量
14.while特殊用法
while read line do 循环体 done < /path/from/somefile
依次读取/path/from/somelife 文件中的每一行,且将行赋值给变量line
15.case...esac
- case...esca 是一种多分支选择结构
-
case语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令。
case VALUE inmode1)command 1command 2command 3;;mode2)command1command2command3;;esac取值后面必须为关键字in,每一模式必须以右括号结束。取值可以为变量或常数。 ;; 与其他语言中的break 类似,意思是跳到整个case语句的最后。