一、shell简介
静态语言:编译型语言
C、C++、JAVA、C#
动态语言:解释型语言
边解释边执行
PHP、SHELL、python、perl
面向过程:Shell,
变量:内存空间,命名
内存:编址的存储单元
图形化界面:Gnome, KDE, Xfce
命令行界面: sh, csh, ksh, bash, tcsh, zsh
Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以
创建shell脚本文件:
打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好。
执行shell脚本的方式:
1、 ./test.sh(我习惯于在当前工作目录下执行,且该文件已有执行权限,即:chmod +x test.sh)
2、 以绝对路径的方式去执行脚本
/test/test.sh
3、直接使用bash或者sh来执行脚本
bash test.sh
sh test.sh
二、变量类型:事先确定数据的存储格式和长度
字符
数值
整型
浮点型
bash支持的引号:
``: 命令替换
"": 强引用,可以实现变量替换
'': 弱引用,不完成变量替换
文件名通配, globbing
*: 任意长度的任意字符
?:任意单个字符
[ ]:匹配指定范围内的任意单个字符
[abc], [a-m], [a-z], [A-Z], [0-9], [a-zA-Z], [0-9a-zA-Z]
[:space:]:空白字符
[:punct:]:标点符号
[:lower:]:小写字母
[:upper:]: 大写字母
[:alpha:]: 大小写字母
[:digit:]: 数字
[:alnum:]: 数字和大小写字母
[^]: 匹配指定范围之外的任意单个字符
[[:alpha:]]*[[:space:]]*[^[:alpha:]]
练习:;
1、显示所有以a或m开头的文件;
ls [am]*
2、显示所有文件名中包含了数字的文件;
ls *[0-9]*
ls *[[:digit:]]*
3、显示所有以数字结尾且文件名中不包含空白的文件;
ls *[^[:space:]]*[0-9]
4、显示文件名中包含了非字母或数字的特殊符号的文件;
ls *[^[:alnum:]]*
三、grep, egrep, fgrep
grep: 根据模式搜索文本,并将符合模式的文本行显示出来。
Pattern: 文本字符和正则表达式的元字符组合而成匹配条件
grep [options] PATTERN [FILE...]
-i
--color
-v: 显示没有被模式匹配到的行
-o:只显示被模式匹配到的字符串
-E: 使用扩展正则表达式
正则表达式:
.: 匹配任意单个字符
[]: 匹配指定范围内的任意单个字符
[^]:匹配指定范围外的任意单个字符
字符集合:[:digit:], [:lower:], [:upper:], [:punct:], [:space:], [:alpha:], [:alnum:]
匹配次数(贪婪模式):
*: 匹配其前面的字符任意次
a, b, ab, aab, acb, adb, amnb
a*b, a\?b
a.*b
.*: 任意长度的任意字符
\?: 匹配其前面的字符1次或0次,例如:\{1\}
\{m,n\}:匹配其前面的字符至少m次,至多n次。例如:\{0,3\}
位置锚定:
^: 锚定行首,此字符后面的任意内容必须出现在行首
$: 锚定行尾,此字符前面的任意内容必须出现在行尾
^$: 空白行
\<或\b: 锚定词首,其后面的任意字符必须作为单词首部出现
\>或\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现
练习:
test.txt文件的内容可以由其他系统文件通过追加重定向导入(例如cat /etc/passwd >> test.txt)
1、显示test.txt文件中以不区分大小的s开头的行;
grep -i '^s' test.txt
grep '^[sS]' test.txt
2、显示test.txt中以nologin结尾的行;
grep ‘nologin$’ test.txt
3、显示test.txt中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;
grep "^#[[:space:]]\{1,\}[^[:space:]]" test.txt
4、显示test.txt中包含了:一个数字:(即两个冒号中间一个数字)的行;
grep ':[0-9]:' test.txt
5、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;
grep '^\([0-9]\).*\1$' test.txt
扩展正则表达式:
字符匹配:
[]
[^]
次数匹配:
*:
?:
+: 匹配其前面的字符至少1次
{m,n}
位置锚定:
^
$
\<
\>
分组:
():分组
\1, \2, \3, ...
或者
|: or
C|cat: Cat或cat, C或cat
grep -E = egrep
四、逻辑运算符
逻辑:1+1>2
逻辑运算:与、或、非、异或
1: 真
0: 假
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
1 & 1 = 1
或:
非:
! 真 = 假
! 假 = 真
命令的间逻辑关系:
逻辑与: &&
第一个条件为假时,第二条件不用再判断,最终结果已经有;
第一个条件为真时,第二条件必须得判断;
逻辑或: ||
脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序
测试脚本是否有语法错误:
bash -x 脚本:单步执行。效果如下图:
#!/bin/bash
# 注释行,不执行
/dev/null: 软件设备, bit bucket,数据黑洞
脚本在执行时会启动一个子shell进程;
命令行中启动的脚本会继承当前shell环境变量;
系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量;
五、bash变量类型:
环境变量
本地变量(局部变量)
位置变量
特殊变量
变量名称:
1、只能包含字母、数字和下划线,并且不能数字开头;
2、不应该跟系统中已有的环境变量重名;
3、最好做到见名知义;
本地变量:
set VARNAME=VALUE: 作用域为整个bash进程;
局部变量:
local VARNAME=VALUE:作用域为当前代码段;
环境变量:作用域为当前shell进程及其子进程;
export VARNAME=VALUE
VARNAME=VALUE
export VARNAME“导出”
位置变量:
$1, $2, ...
Shift
特殊变量:
$?: 上一个命令的执行状态返回值;
程序执行,可能有两类返回值:
程序执行结果
程序状态返回代码(0-255)
0: 正确执行
1-255:错误执行,1,2,127系统预留;
$# 参数个数
$* 遍历所有参数
$@ 遍历所有参
$$ 进程id
$0 脚本名称
输出重定向:
> 输出重定向
>> 输出追加重定向
2> 错误重定向
2>> 错误追加重定向
&> 完全重定向
&>>
<
<< 指定终止结束符
六、条件判断
bash中如何实现条件判断?
单分支if语句
if 判断条件; then
statement1
statement2
...
fi
双分支的if语句:
if 判断条件; then
statement1
statement2
...
else
statement3
statement4
...
fi
多分支的if语句:
if 判断条件1; then
statement1
...
elif 判断条件2; then
statement2
...
elif 判断条件3; then
statement3
...
else
statement4
...
fi
条件测试类型:
整数测试
字符测试
文件测试
条件测试的表达式:
[ expression ]
[[ expression ]]
test expression
如果test.txt文件的行数大于100,就显示big;
[ `wc -l test.txt | cut -d' ' -f1` -gt 100 ] && echo "big"
整数比较:
-eq: 测试两个整数是否相等;比如 $A -eq $B
-ne: 测试两个整数是否不等;不等,为真;相等,为假;
-gt: 测试一个数是否大于另一个数;大于,为真;否则,为假;
-lt: 测试一个数是否小于另一个数;小于,为真;否则,为假;
-ge: 大于或等于
-le:小于或等于
字符串比较:
= 等于,如:if [ "$a" = "$b" ]
== 等于,如:if [ "$a" == "$b" ], 与=等价
!= 不等于,如:if [ "$a" != "$b" ], 这个操作符将在[[]]结构中使用模式匹配.
练习,写一个脚本,完成以下要求:
给定一个用户:
1、如果其UID为0,就显示此为管理员;
2、否则,就显示其为普通用户;
如果 UID为0;那么
显示为管理员
否则
显示为普通用户
Uid.sh:
“引用”一个命令的执行结果,要使用命令引用;比如:
a=`wc-l test.txt | cut -d: -f1`;
使用一个命令的执行状态结果,要直接执行此命令,一定不能引用;
如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=`id -u user1`;
如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如
id -u user1
a=$?
此句绝对不可以写为a=`id -u user1`;
练习:写一个脚本
给定一个文件,比如/etc/inittab
判断这个文件中是否有空白行;
如果有,则显示其空白行数;否则,显示没有空白行。
Kongbaihang.sh:
七、shell中进行算术运算:
A=3
B=6
1、let 算术运算表达式
let C=$A+$B
2、$[算术运算表达式]
C=$[$A+$B]
3、$((算术运算表达式))
C=$(($A+$B))
4、expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
C=`expr $A + $B`
八、文件测试:
-e FILE:测试文件是否存在
-f FILE: 测试文件是否为普通文件
-d FILE: 测试指定路径是否为目录
-r FILE: 测试当前用户对指定文件是否有读取权限;
[ -e test.txt ]
九、参数传递
例如:./filetest.sh 3 4
$1: 3
$2: 4
练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积;
Canshu.sh:
十、字符测试、参数传递
字符测试:
==:测试是否相等,相等为真,不等为假
!=: 测试是否不等,不等为真,等为假
>
<
-n string: 测试指定字符串是否为空,空则真,不空则假
-z string: 测试指定字符串是否不空,不空为真,空则为假
参数传递:
练习:写一个脚本
传递一个参数(单字符就行)给脚本,如参数为q、Q、quit或Quit,就退出脚本;否则,就显示用户的参数;
Chuancan.sh:
十一、for循环
循环:进入条件,退出条件
for 变量 in 列表; do
循环体
done
遍历完成之后,退出;
如何生成列表:
for i in{ 1..100};do
循环体
done
`seq [起始数 [步进长度]] 结束数`
例如`seq 1 2 12`
练习:写一个脚本,完成以下任务
1.创建10个系统账号user1-user10
2.设置密码是随机数(字符和数字结合)
3.将生成的账号和密码输出到一个文件中
Useradd.sh:
写一个脚本:
计算100以内所有能被3整除的正整数的和;
Test.sh:
写一个脚本:
计算100以内所有奇数的和以及所有偶数的和;分别显示之;
100.sh:
十二、组合测试条件
-a: 与关系
-o: 或关系
!: 非关系
if [ $# -gt 1 -a $# -le 3 ]
if [ $# -gt 1 ] && [ $# -le 3 ]
十三、文本处理工具sed
grep, sed(流编辑器), awk
sed基本用法:
sed: Stream EDitor
行编辑器 (全屏编辑器: vi)
sed: 模式空间
默认不编辑原文件,仅对模式空间中的数据做处理;而后,处理结束后,将模式空间打印至屏幕;
sed [options] 'AddressCommand' file ...
-n: 静默模式,不再默认显示模式空间中的内容
-i: 直接修改原文件
-e SCRIPT -e SCRIPT:可以同时执行多个脚本
-r: 表示使用扩展正则表达式
例如下图是原文件内容
sed ‘s/w/a/g’ text.txt 不会修改源文件
sed -i ‘s/w/a/g’ text.txt 第二行开头的w被改为a
一些使用方法:
1、StartLine,EndLine
比如1,100
2、/pattern1/,/pattern2/
第一次被pattern1匹配到的行开始,至第一次被pattern2匹配到的行结束,这中间的所有行
3、LineNumber
指定的行
4、StartLine, +N
从startLine开始,向后的N行;
Command:
d: 删除符合条件的行;
p: 显示符合条件的行;
a \string: 在指定的行后面追加新行,内容为string
\n:可以用于换行
sed '/^U/a \#hello\n#word' test.txt
i \string: 在指定的行前面添加新行,内容为string
sed '/^U/i \#hello\n#word' test.txt
w FILE: 将地址指定的范围内的行另存至指定的文件中;
sed '/^#/w /root/txt' test.txt
s/pattern/string/修饰符: 查找并替换,默认只替换每行中第一次被模式匹配到的字符串
sed 's/#/@/g' test.txt
加修饰符
g: 全局替换
将文本中的#换成@
s///=s###=s@@@
sed练习:
test.txt文件的内容可以由任意其他系统文件通过追加重定向导入(例如cat /etc/passwd >> test.txt)
1、删除test.txt文件中行首的空白符;
sed -r 's@^[[:spapce:]]+@@g' test.txt
2、替换test.txt文件中"id:3:initdefault:"一行中的数字为5;
sed 's@\(id:\)[0-9]\(:initdefault:\)@\15\2@g' test.txt
3、删除test.txt文件中的空白行;
sed '/^$/d' test.txt
4、删除test.txt文件中开头的#号;
sed 's@^#@@g' test.txt
5、删除某文件中开头的#号及后面的空白字符,但要求#号后面必须有空白字符;
sed -r 's@^#[[:space:]]+@@g' test.txt
6、删除某文件中以空白字符后面跟#类的行中的开头的空白字符及#
sed -r 's@^[[:space:]]+#@@g' test.txt
十四、监控某个磁盘使用率的简单脚本