SHELL编程笔记
1 普通变量
略
2 系统专用变量
shell在初始化的时候会在执行profile等初始化脚本,脚本中定义了一些环境变量,这些变量会在创建子进程时传递给子进程。
用env命令可以查看当前的环境变量。常用的系统环境变量如下:
_(下划线) 上一条命令的最后一个参数
变量名称 |
描述 |
$UID |
展开为当前用户的用户ID,在shell启动时初始化 |
$HOME |
|
$USER |
当前用户 |
$TMOUT |
在无操作情况下的超时时间【秒】 |
$PATH |
|
$GROUPS |
当前用户所属的组 |
$BASH |
展开为调用bash实例时使用的全路径名 |
$CDPATH |
|
$SHELLOPTS |
包含一列开启的shell选项,比如braceexpand、hashall、monitor等 |
$SHELL |
当调用shell时,它扫描环境变量以寻找该名字。shell给PATH、PS1、PS2、MAILCHECK和IFS设置默认值。HOME和MAIL由login(1)设置 |
PS1 |
主提示符串,默认值是$ |
PS2 |
次提示符串,默认值是> |
PS3 |
与select命令一起使用的选择提示符串,默认值是#? |
PS4 |
当开启追踪时使用的调试提示符串,默认值是+。追踪可以用set –x开启 |
EUID |
展开为在shell启动时被初始化的当前用户的有效ID |
HISTFILE |
指定保存命令行历史的文件。默认值是~/.bash_history。如果被复位,交互式shell退出时将不保存命令行历史 |
HISTSIZE |
记录在命令行历史文件中的命令数。默认是500 |
3 命令作为变量
3.1 反引号``的方式
cmd=`date`
3.2 $(cmd)的形式
cmd=$(date)
4 特殊变量
$0:获取当前执行shell脚本的文件名,包含脚本的路径
$n:获取执行当前脚本的第n个参数n=1..9 ,如果需要获取大于10的参数那么需要用{}比如${10}
$#:获取执行脚本传递过来的参数个数 (如上图所示)
$*:获取当前shell的所有参数,将所有的命令行参数视为当个字符串,相当于“$1$2$3......”
[email protected]:获取当前shell的所有参数,将每个参数视为独立的字符串
$?:当前shell进程中,上一个命令的返回值,如果上一个命令成功执行则$?的值为0,否则为其他非零值,常用做if语句条件
$?返回值参考:
返回码 |
描述 |
0 |
表示执行成功 |
1 |
表示权限不够 |
2~125 |
表示运行失败,脚本命令,系统命令错误或参数传递错误 |
126 |
找到该命令,但是无法执行 |
127 |
未找到要执行的命令 |
>128 |
命令被系统强制结束 |
$$:当前shell进程的pid
$!:上一个指令的pid
$-:显示shell使用的当前选项
$_:之前命令的最后一个参数
$* 和[email protected] 案例:
设置参数:
set -- "i am " hunan hailong
查看参数个数:$#
for i in $*; do echo $i ; done
$*没有带引号,程序会将$*分别打印出来【并且会解析”i am“】
for i in [email protected]; do echo $i ; done
从以上结果可以看出 在没有双引号的情况下[email protected]和$*的效果是一样的
for i in "$*"; do echo $i ; done
带有双引号的$* 会将所有数据当成当个字符串
for i in "[email protected]"; do echo $i ; done
带有双引号的[email protected] 会将所有数据当成当个字符串,并且如果没有in 默认情况下是"[email protected]"
即:for i 等价于 for i in "[email protected]"
$* 和[email protected]总结:
1 如果$*和[email protected]带引号的话,那么$* 会把所有的参数当做一个字符串,而[email protected]会认为是多个参数
5 变量子串的常用操作
常用操作如下表:
表达式 |
说明 |
${#string} |
返回$string的长度 |
${string:position} |
在$string中,从位置$postion之后开始提取子串 |
${string:position:length} |
在$string中,从位置$postion之后开始提取长度为$length的字串 |
${string#substring} |
从变量$string开头开始删除最短匹配$substring子串 |
${string##substring} |
从变量$string开头开始删除最长匹配$substring子串 |
${string%substring} |
从变量$string结尾开始删除最短匹配$substring子串 |
${string%%substring} |
从变量$string结尾开始删除最长匹配$substring子串 |
${string/substring/replace} |
使用$replace,来替换第一个匹配的$substring |
${string/#substring/replace} |
如果$string前缀匹配$substring,就使用$replace来替代匹配的$substring |
${string/%substring/replace} |
如果$string后缀匹配$substring,就使用$replace来替代匹配的$substring |
举例说明:
定义一个变量内容为:name="i am hailong"
返回name的长度
提取字符串:
6 其他变量的替换
交替变量替换表:
运算符号 |
替换 |
${value:-word} |
如果变量名存在且为非null,则返回变量的值,否则返回word字符串。 用途:如果变量不存在,则返回默认值 |
${value:=word} |
如果变量名存在且为非null,则返回变量的值,否则设置这个变量值为word,并返回其值 |
${value:?"not defined" |
如果变量名存在且为非null,则返回变量的值,否则显示变量名:message,并退出当前的命令或者脚本 |
${value:+word} |
如果变量名存在且为非null,则返回变量的值,否则返回null 用途:测试变量是否存在 |
7 变量耗时对比
获取字符串长度的三种方法
name="yuanhailong"
1 echo ${#name}
2 echo $name | wc -m
3 echo ${expr length "$name"}
利用time命令检查耗时:
生成数据:
${#chars}
time for i in $(seq 11111);do count=${#chars};done;
wc -m
time for i in $(seq 11111);do count=`echo ${chars} | wc -m`; done;
expr length "$chars"
time for i in $(seq 11111);do count=`expr length "$chars"`; done;
从以上结果对比中可以看出 ${#chars}效率要比其他两种方式高出几十倍甚至上百倍。
8 变量的数值计算
变量的数值计算常用有以下几个命令:
(()) let expr bc $[]
let和(())是一样的 但是let的效率比(())低
小案例:
利用expr 判断判断是否为整数
bc命令的用法:
bc是unix下的计算器,他可以用在命令行下面:
计算器
判断字符串是否为数字的多种方法
-z -n -o -a的含义
-z 表示字符串为null,即指定字符串长度为0
-n 表示字符串不为null
-o 表示两个表达式中只要一个一个成立就为真
-a 表示两个表达式中都要真才返回真
9 条件测试
条件测试语法:
在basha的各种流程控制结构中通常需要进行各种测试,然后根据测试执行不同的操作,有事也会通过与if等条件语句相结合,使我们可以方便的完成判断。
【语法说明】
格式1: test <测试表达式>
格式2: [<测试表达式>]
格式3:[[测试表达式]]
说明:
格式1和格式2是等价的。
格式3为扩展的test命令。
提示:
在[[]]中可以使用通配符进行模式匹配。 && ,||,>,<等操作符可以应用于[[]]中,但是不能应用于[]中。
对整数进行关系运算,也可以使用shell运算符(())
对test<>进行测试
test -f file && echo true || echo false
利用!可以对结果取反
test ! -f file && echo true || echo false
对[]进行测试
[ -f file ] && echo true || echo false
取反
[ ! -f file ] && echo true || echo false
对[[]]进行测试
[[ -f file ]] && echo true || echo false
文件测试操作符
在书写测试表达式的时,可以使用下表中的文件操作符
常用文件操作符号 |
说明 |
-f 文件 |
若文件存在且为普通文件则为真 |
-d 文件 |
若文件存在且为目录则为真 |
-s 文件 |
若文件存在且不为空(文件大小大于0)则为真 |
-e 文件 |
若文件存在则为真(注意和-f的区别) |
-r 文件 |
若文件存在且可读则为真 |
-w 文件 |
若文件存在且可读则为真 |
-x 文件 |
若文件存在且可执行则为真 |
-L 文件 |
若文件存在且为链接文件则为真 |
f1 -nt f2 |
若文件f1比f2要新则为真 |
f1 -ot f2 |
若文件f1比f2要旧则为真 |
字符串测试操作符
字符串测试操作符的作用是:比较两个字符串是否相同,字符串长度是否为0,字符串是否为null(注:bash区分零长度字符串和空字符串)等
“=”比较2个字符串是否相等,与==等价, 如[ “$a”=="$b" ] ,其中$a这样的变量最好用""括起来,因为中间有空格,*等符号就可能出错了,当然更好的方法是[ "${a}"="${b}" ] "!=" 比较两个字符串是否相同,不同则为“是”
在书写表达式时,可以使用下表的操作符:
常用字符串测试字符 |
说明 |
-z "字符串" |
若长度为0则为真, -z 可以理解为zero |
-n "字符串" |
若长度不为0则为真,和-z相反 |
"串1"="串2" |
若串1等于串2 则为真,可以使用"=="替代"=" |
"串1"="串2" |
若串1不等于串2 则为真 |
特别注意:以上表格中的字符串测试操作符号务必用""引起来
整数二元比较操作符
在[]使用比较符 |
在(())和[[]]中使用比较符 |
说明 |
-eq |
== |
equal的缩写,相等 |
-ne |
!= |
not equal的缩写,不相等 |
-gt |
> |
大于 |
-ge |
>= |
大于等于 |
-lt |
< |
小于 |
-le |
<= |
小于等于 |
提示:
1) “<”意思是小于,if[[ "$a" < "$b" ]],if[ "$a" \< "$b" ] 在[]中需要转义,因为在shell中<也用<和>重定向
2) ">" 意思是小于,if[[ "$a" > "$b" ]],if[ "$a" \> "$b" ] 在[]中需要转义,因为在shell中<也用<和>重定向
3) "=" 意思是等于 ,if[[ "$a" = "$b" ]],if[ "$a" = "$b" ] 在[]中不需要转义
经过实践,“=”和“!=”在[]中不需要转义,但是">"和"<"在[]中需要使用转义符,对于数字不使用转义符未必会报错,但是结果可能会不对
逻辑操作符
在[]使用逻辑操作符 |
在(())和[[]]中使用逻辑操作符 |
说明 |
-a |
&& |
与 |
-o |
|| |
或 |
! |
! |
非 |
10分支域循环结构
注: 如果 [条件]和then在一行需要用分号 如果不在一行不需要分号
case语句
语法
case "字符串变量" in
value1) 指令
..........
;;
value2) 指令
........
;;
*) 指令
,.,.....
esac
加颜色
提示:while循环是条件满足才回执行,until循环是直到条件满足就退出
案例
11 shell中的函数
语法:
func_name () {
......
}
或者
function func_name(){
.......
}
函数调用
1 func_name #注意调用函数的时候不要带() 可以考虑下和python或java有什么区别
2 func_name 参数1 参数2 .....
【带参数函数说明】
1) 在函数体中参数位置($1,$2,$3..... $#,$? 等) 都可以是函数的参数
2) 父脚本的参数则临时的被函数参数所覆盖
3) $0比较特殊,它依旧是父脚本的参数
4) 当函数完成时,原来的命令行参数会恢复
5) 在shell函数里面,return和exit是一样的,用于跳出循环
6) 在shell函数里面,exit会使得整个shell脚本种植
7) return 语句会返回一个退出之给调用程序
函数练习:
函数和执行体分离
1 创建一个名叫做hailong_fun.sh脚本 里面包含如下:
2 给hailong_fun.sh赋予执行权限
3 编写调用函数 比如fun.sh
4 调用
12 shell数组
数组介绍
简单来说,数组就是相同数据类型的元素按一定顺序排列的集合。
数组就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们区分他们的变量的集合。这个名字成为数组名,编号成为下标。组成数组的各个变量成为数组的分量,也成为数组的元素,有事也成为下表变量。
如果有过其他语言编程经历,那么想必会熟悉数组的概念。由于有了数组,可以用相同的名字引用一系列的变量,并用数字(索引)来识别他们。在许多场合,使用数组可以缩短和简化程序,因为可以利用索引设计一个循环,高校处理多种情况
数组定义和读取
方法1:array=(value1 value2 value3 ....) 【元素之间用空格分割】
打印数组元素
echo ${array[1]}
数组赋值
array[3]=4
数组的删除
直接通过 unset array[index]可以删除数据
数组的截取和替换
数组实战案例
1 将当前目录下的文件用数组的方式打印
2 检查URL脚本
13 shell脚本的调试
提示:你检查脚本明明没有问题,但就是执行出现莫名其妙的语法错误,要想到执行dos2unix格式化一下。