第三周
欲练此功,必先自宫
shell
创建shell脚本
- 第一步:使用文本编辑器来创建文本文件
- 第一行必须包括shell声明序列:#!
示例:#!/bin/bash - 添加注释: 注释以#开头
- 第二步:运行脚本
给予执行权限,在命令行上指定脚本的绝对或相对路径
直接运行解释器,将脚本作为解释器程序的参数运行脚本规范
1.第一行一般为调用使用的语言
2.程序名,避免更改文件名为无法找正确的文件
3.版本号
4.更改后的时间
5.作者相关信息
6.该程序的作用,及注意事项
7最后是各版本版本的更新简要说明编写⽣成脚本基本格式的脚本,包括作者,联系⽅式,版本,时间,描述等
set ignorecase set cursorline set autoindent autocmd BufNewFile *.sh exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2,"#") call setline(3,"#****************************************************") call setline(4,"#Author: wlp ") call setline(5,"#QQ: 449099995") call setline(6,"#Date: ".strftime("%Y-%m-%d")) call setline(7,"#FileName: ".expand("%")) call setline(8,"#URL: ") call setline(9,"#Description: The test script") call setline(10,"#Copyright (C): ".strftime("%Y")." All rights reserved") call setline(11,"#***************************************************") call setline(12,"") endif endfunc autocmd BufNewFile * normal G
脚本中的变量
Shell中变量命名法则:
- 1、不能使程序中的保留字:例如if, for
- 2、只能使用数字、字母及下划线,且不能以数字开头
- 3、见名知义
- 4、统一命名规则:驼峰命名法
Shell中命名建议规则:
- 1、变量名大写
- 2、局部变量小写
- 3、函数名小写
- 4、用英文名字,并体现出实际作用
局部变量
变量赋值:name=‘value’
可以使用引用value - (1) 可以是直接字串:name=“root"
- (2) 变量引用:name="$USER"
- (3) 命令引用:name=
COMMAND
name=$(COMMAND)
变量引用:${name} 或者 $name
- " " 弱引用,其中的变量引用会被替换为变量值
-
' ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
显示已定义的所有变量:set删除变量:unset name
单引号、双引号、反向单引号区别:
- 1、由单引号('),强引用,其中的变量会被替换未变量值。
- 2、由双引号("),弱引用,其中的变量不会被替换未变量值,而保持原字符串。
- 3、反向单引号(`)括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准 输出结果取代整个反引号(包括两个反引号)部分。
环境变量
变量声明、赋值:
- export name=VALUE
- declare -x name=VALUE
变量引用: $name, ${name}
显示所有环境变量:env printenv export declare -x
删除变量: unset name
只读变量:
只读变量:只能声明,但不能修改和删除
声明只读变量:
- readonly name
- declare -r name
查看只读变量:- readonly -
位置变量:
位置变量:在脚本代码中调用通过命令行传递给脚本的参数
- readonly -
- $1, $2, ... 对应第1、第2等参数,shift [n]换位置
- $0 命令本身
- $* 传递给脚本的所有参数,全部参数合为一个字符串
- $@ 传递给脚本的所有参数,每个参数为独立字符串
- $# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异 - set -- 清空所有位置变
退出状态:
进程使用退出状态来报告成功或失败0 代表成功,1-255代表失败$? 变量保存近的命令退出状态
bash自定义退出状态码
exit [n]:自定义退出状态码
算术运算:
bash中的算术运算:help let
- +, -, *, /, %取模(取余), **(乘方),乘法符号有些场景中需要转义
实现算术运算:
- (1) let var=算术表达式
- (2) var=$[算术表达式]
- (3) var=$((算术表达式))
- (4) var=$(expr arg1 arg2 arg3 ...)
- (5) declare –i var = 数值
- (6) echo ‘算术表达式’ | bc
bash有内建的随机数生成器变量:$RANDOM(0-32767)
- 示例:生成 0 - 49 之间随机数
- echo $[$RANDOM%50]
赋值:
增强型赋值:
- +=, -=, *=, /=, %=
let varOPERvalue
- 例如:let count+=3
自加3后自赋值
自增,自减:
- let var+=1
- let var++
- let var-=1
- let var--
条件测试:
判断某需求是否满足,需要由测试机制来实现。专用的测试表达式需要由测试命令辅助完成测试过程 评估布尔声明,以便用在条件性执行中
若真,则返回0
若假,则返回1
测试命令:
- test EXPRESSION
- [ EXPRESSION ]
- [[ EXPRESSION ]]
-
注意:EXPRESSION前后必须有空白字符
数值测试:
- -v VAR
变量VAR是否设置
数值测试:
- -gt 是否大于
- -ge 是否大于等于
- -eq 是否等于
- -ne 是否不等于
- -lt 是否小于
- -le 是否小于等于
字符串测试
- = 是否等于
- > ascii码是否大于ascii码
- < 是否小于
- != 是否不等于
- =~ 左侧字符串是否能够被右侧的PATTERN所匹配
- 注意: 此表达式一般用于[[ ]]中;扩展的正则表达式
- -z "STRING“ 字符串是否为空,空为真,不空为假
- -n "STRING“ 字符串是否不空,不空为真,空为假
⽂件存在性和类型测试
存在性测试
- -a FILE:同-e
- -e FILE: 文件存在性测试,存在为真,否则为假
存在性及类别测试
- -b FILE:是否存在且为块设备文件
- -c FILE:是否存在且为字符设备文件
- -d FILE:是否存在且为目录文件
- -f FILE:是否存在且为普通文件
- -h FILE 或 -L FILE:存在且为符号链接文件
- -p FILE:是否存在且为命名管道文件
- -S FILE:是否存在且为套接字文件
⽂件权限测试:
- -r FILE:是否存在且可读
- -w FILE: 是否存在且可写
- -x FILE: 是否存在且可执行
⽂件特殊权限测试
- -u FILE:是否存在且拥有suid权限
- -g FILE:是否存在且拥有sgid权限
- -k FILE:是否存在且拥有sticky权限
⽂件属性测试
文件大小测试:
- -s FILE: 是否存在且非空
文件是否打开:
- -t fd: fd 文件描述符是否在某终端已经打开
- -N FILE:文件自从上一次被读取之后是否被修改过
- -O FILE:当前有效用户是否为文件属主
- -G FILE:当前有效用户是否为文件属组
双目测试:
- FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
- FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
- FILE1 -ot FILE2: FILE1是否旧于FILE2
组合测试
第一种方式:
- EXPRESSION1 -a EXPRESSION2 并且
- EXPRESSION1 -o EXPRESSION2 或者
- ! EXPRESSION
必须使用测试命令进行,[[ ]] 不支持
第二种方式:
- COMMAND1 && COMMAND2 并且,短路与,代表条件性的AND THEN
- COMMAND1 || COMMAND2 或者,短路或,代表条件性的OR ELSE
- ! COMMAND 非
如:[ -f “$FILE” ] && [[ “$FILE”=~ .*.sh$ ]]read命令:
使用read来把输入值分配给一个或多个shell变量
- -p 指定要显示的提示
- -s 静默输入,一般用于密码
- -n N 指定输入的字符长度N
- -d ‘字符’ 输入结束符
- -t N TIMEOUT为N秒
- read 从标准输入中读取值,给每个单词分配一个变量。所有剩余单词都被分配给后一个变量
- read -p "Enter a filename: " FILE
[ ]和[[ ]] 的区别
[ ] 实际上是bash 中 test 命令的简写。即所有的 [ expr ] 等于 test expr。对 test 命令来说, 用 -eq 要进行数字比较,而你此时传入字符串,就报错了。
[[ expr ]] 是bash中真正的条件判断语句,其语法更符合编程习惯 (比如 &&, || 的用法),虽然我认 为在 [[ ]] 中 故意传字符串给 -eq 也应该像 test 一样报错,但是显然bash实现中直接把非整数的字符串直 接转换成了 0 (你可以自行验证,在 [[ ]] 中的,任何需要整数,但是提供的确又是其他不能转换成整数的字 符串,都变成了0)。 这应该是bash实现中的没有对 [[ ]] 中 -eq 操作符两边的内容进行检查导致的。
判断语句()、 (( ))和{}的区别。
1、单⼩括号 ()
①命令组。括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。括 号中多个命令之间用分号隔开,后一个命令可以没有分号,各命令和括号之间不必有空格。
②命令替换。等同于cmd
,shell扫描一遍命令行,发现了$(cmd)结构,便将$(cmd)中的cmd执行一次,得到 其标准输出,再将此输出放到原来命令。有些shell不支持,如tcsh。
③用于初始化数组。如:array=(a b c d)
2、双⼩括号 (( ))
①整数扩展。这种扩展计算是整数型的计算,不支持浮点型。((exp))结构扩展并计算一个算术表达式的值, 如果表达式的结果为0,那么返回的退出状态码为1,或者 是"假",而一个非零值的表达式所返回的退出状态码将 为0,或者是"true"。若是逻辑判断,表达式exp为真则为1,假则为0。
②只要括号中的运算符、表达式符合C语言运算规则,都可用在$((exp))中,甚至是三目运算符。作不同进位 (如二进制、八进制、十六进制)运算时,输出结果全都自动转化成了十进制。如:echo $((16#5f)) 结果为95 (16进位转十进制)
③单纯用 (( )) 也可重定义变量值,比如 a=5; ((a++)) 可将 $a 重定义为6
④常用于算术运算比较,双括号中的变量可以不使用$符号前缀。括号内支持多个表达式用逗号分开。 只要括
号中的表达式符合C语言运算规则,比如可以直接使用for((i=0;i<5;i++)), 如果不使用双括号, 则为for i in seq 0 4
或者for i in {0..4}。再如可以直接使用if (($i<5)), 如果不使用双括号, 则为if [ $i -lt 5 ]。
(1)单小括号,(cmd1;cmd2;cmd3) 新开一个子shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 后一个命令后可以没有分号。
(2)单大括号,{ cmd1;cmd2;cmd3;} 在当前shell顺序执行命令cmd1,cmd2,cmd3, 各命令之间用分号隔开, 后一个命令后必须有分号, 第一条命令和左括号之间必须用空格隔开。
3、⼤括号、花括号 {}
①大括号拓展。(通配(globbing))将对大括号中的文件名做扩展。在大括号中,不允许有空白,除非这个空白 被引用或转义。第一种:对大括号中的以逗号分割的文件列表进行拓展。如 touch {a,b}.txt 结果为a.txt b.txt。第二种:对大括号中以点点(..)分割的顺序文件列表起拓展作用,如:touch {a..d}.txt 结果为 a.txt b.txt c.txt d.txt
# ls {ex1,ex2}.sh
ex1.sh ex2.sh
# ls {ex{1..3},ex4}.sh
ex1.sh ex2.sh ex3.sh ex4.sh
# ls {ex[1-3],ex4}.sh
ex1.sh ex2.sh ex3.sh ex4.sh
②代码块,又被称为内部组,这个结构事实上创建了一个匿名函数 。与小括号中的命令不同,大括号内的命令 不会新开一个子shell运行,即脚本余下部分仍可使用括号内变量。括号内的命令间用分号隔开,后一个也必须 有分号。{}的第一个命令和左括号之间必须要有一个空格。
建⽴条件脚本
1、条件选择if语句
选择执行:
注意:if语句可嵌套
- 单分支
if 判断条件;then
条件为真的分支代码
fi
- 双分支
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi - 多分支
if 判断条件1; then
条件1为真的分支代码
elif 判断条件2; then ``
条件2为真的分支代码
elif 判断条件3; then
条件3为真的分支代码
else
以上条件都为假的分支代码
fi
逐条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句2、条件判断:case语句
case 变量引用 in
PAT1)
分支1
;
PAT2)
分支2
;
...
)
esac
case支持glob风格的通配符:
:任意长度任意字符
?:任意单个字符
[]:指定范围内的任意单个字符
a|b: a或b3、bash如何展开命令⾏
把命令行分成单个命令词
展开别名
展开大括号的声明({})
展开波浪符声明(~)
命令替换$() 和 ``)
再次把命令行分成命令词
展开文件通配(*、?、[abc]等等)
准备I/0重导向(<、>)
运行命令4、防⽌扩展
- 反斜线(\)会使随后的字符按原意解释
echo Your cost: \$5.00
Your cost: $5.00 - 加引号来防止扩展
• 单引号(’’)防止所有扩展
• 双引号(”“)也可防止扩展,但是以下情况例外:
$(美元符号) 变量扩展
\(反斜线) 禁止单个字符扩展
!(叹号) 历史命令替换5、bash的配置⽂件。按⽣效范围划分,存在两类:
-
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc 个人配置:
~/.bash_profile
~/.bashrc - 修改profile和bashrc文件后需生效
1重新启动shell进程
2 . 或source6、set 命令
-
$- 变量
h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h 选项关闭
i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的shell。所谓的交互式 shell,在脚本中,i选项是关闭的。
m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。
B:braceexpand,大括号扩展
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上近的一 个历史命令,“!n”返回第 n 个历史命令 - set 命令
-u 在扩展一个没有设置的变量时,显示错误信息,等同set –o nounset
-e 如果一个命令返回一个非0退出状态值(失败)就退出,等同set –o errexit
find
使用find命令在多条件限定下查找符合条件的文件
指搜索层级
- -maxdepth level 大搜索目录深度,指定目录为第1级
- -mindepth level 小搜索目录深度
先处理目录内的文件,再处理目录
- -depth 根据文件名和inode查找:
- -name "文件名称":支持使用glob,*, ?, [], [^]
- -iname "文件名称":不区分字母大小写
- -inum n 按inode号查找
- -samefile name 相同inode号的文件
- -links n 链接数为n的文件
- -regex “PATTERN”:以PATTERN匹配整个文件路径,而非文件名
根据属主、属组查找:
- -user USERNAME:查找属主为指定用户(UID)的文件
- -group GRPNAME: 查找属组为指定组(GID)的文件
- -uid UserID:查找属主为指定的UID号的文件
- -gid GroupID:查找属组为指定的GID号的文件
- -nouser:查找没有属主的文件
- -nogroup:查找没有属组的文件 根据文件类型查找
- -type TYPE
• f: 普通文件
• d: 目录文件
• l: 符号链接文件
• s:套接字文件
• b: 块设备文件
• c: 字符设备文件
• p: 管道文件 空文件或目录-empty
find /app -type d -empty查找条件
组合条件: 与:-a 或:-o 非:-not !
德·摩根定律:
(非 A) 或 (非 B) = 非(A 且 B)
(非 A) 且 (非 B) = 非(A 或 B)
示例:!A -a !B = !(A -o B) !A -o !B = !(A -a B)根据⽂件⼤⼩来查找
- -size [+|-]#UNIT 常用单位:k, M, G,c(byte)
- #UNIT: (#-1, #] 如:6k 表示(5k,6k]
- -#UNIT:[0,#-1] 如:-6k 表示[0,5k]
- +#UNIT:(#,∞) 如:+6k 表示(6k,∞)
以“天”为单位,
- -atime [+|-]#,
#: [#,#+1)
+#: [#+1,∞]
-#: [0,#) - -mtime -ctime
以“分钟”为单位
- -amin , -mmin , -cmin
根据权限查找:
-
-perm [/|-]MODE
MODE: 精确权限匹配
/MODE:任何一类(u,g,o)对象的权限中只要能一位匹配即可,或关系,+ 从centos7开始淘汰
-MODE:每一类对象都必须同时拥有指定权限,与关系 0 表示不关注- find -perm 755 会匹配权限模式恰好是755的文件
- 只要当任意人有写权限时,find -perm +222就会匹配
- 只有当每个人都有写权限时,find -perm -222才会匹配
- 只有当其它人(other)有写权限时,find -perm -002才会匹配
处理动作
- -print:默认的处理动作,显示至屏幕
- -ls:类似于对查找到的文件执行“ls -l”命令 -delete:删除查找到的文件
- -fls file:查找到的所有文件的长格式信息保存至指定文件中
- -ok COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,对于每个文件执行命令之前,都会交互式 要求用户确认
- -exec COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令
- {}: 用于引用查找到的文件名称自身 find传递查找到的文件至后面指定的命令时,查找到所有符合条件的文件一次性传递给后面的命令
参数替换xargs
- 由于很多命令不支持管道|来传递参数,而日常工作中有这个必要,所以就有了xargs命令 xargs用于产生某个命令的参数,xargs 可以读入 stdin 的数据,并且以空格符或回车符将 stdin 的数据分隔 成为arguments
注意:文件名或者是其他意义的名词内含有空格符的情况
有些命令不能接受过多参数,命令执行可能会失败,xargs可以解决
示例:
ls f* |xargs rm
find /sbin/ -perm +700 |ls -l 这个命令是错误的
find /bin/ -perm /7000 | xargs ls -l 查找有特殊权限的文件
find /bin/ -perm -7000 | xargs ls -l 此命令和上面有何区别?
find和xargs格式:find | xargs COMMAND
压缩归档打包⽂件
compress/uncompress
compress [-dfvcVr] [-b maxbits] [file ...]
- -d 解压缩,相当于uncompress
- -c 结果输出至标准输出,不删除原文件
- -v 显示详情
- uncompress file.Z 解压缩
- zcat file.Z 不显式解压缩的前提下查看文本文件内容
示例:zcat file.Z >filegzip/gunzip
gzip [OPTION]... FILE ...
- -d 解压缩,相当于gunzip
- -c 结果输出至标准输出,保留原文件不改变
- -# 指定压缩比,#取值为1-9,值越大压缩比越大
gunzip file.gz 解压缩
zcat file.gz 不显式解压缩的前提下查看文本文件内容
- 示例:
gzip -c messages >messages.gz
gzip -c -d messages.gz > messages
zcat messages.gz > messages
cat messages | gzip > m.gz
bzip2/bunzip2/bzcat
- -k keep, 保留原文件
- -d 解压缩
- -# 1-9,压缩比,默认为9
bunzip2 file.bz2 解压缩 bzcat file.bz2
不显式解压缩的前提下查看文本文件内容
xz/unxz/xzcat
- 打包压缩 zip –r /backup/sysconfig /etc/sysconfig/
- 解包解压缩 unzip sysconfig.zip
cat/var/log/messages | zip messages
unzip -p message > messagetar⼯具
tar(Tape ARchive,磁带归档的缩写)
tar [OPTION]... - (1) 创建归档
tar -cpvf /PATH/FILE.tar FILE... - (2) 追加文件至归档: 注:不支持对压缩文件追加
tar -r -f /PATH/FILE.tar FILE... - (3) 查看归档文件中的文件列表
tar -t -f /PATH/FILE.tar - (4) 展开归档
tar -x -f /PATH/FILE.tar
tar -x -f /PATH/FILE.tar -C /PATH/ - (5) 结合压缩工具实现:归档并压缩
-j: bzip2, -z: gzip, -J: xz - -exclude 排除文件
tar zcvf /root/a3.tgz --exclude=/app/host1 --exclude=/app/host2 /app - -T 选项指定输入文件 -X 选项指定包含要排除的文件列表
tar zcvf mybackup.tgz -T /root/includefilelist -X /root/excludefilelist - split:分割一个文件为多个文件
split -b Size –d tar-file-name prefix-name
split -b 1M –d mybackup.tgz mybackup-parts
split -b 1M mybackup.tgz mybackup-parts
合并:cat mybackup-parts* > mybackup.tar.gz
cpio
功能:复制文件从或到归档 cpio命令是通过重定向的方式将文件进行打包备份,还原恢复的工具,它可以解压以“.cpio”或者“.tar”结尾的文 件
cpio [选项] > 文件名或者设备名
cpio [选项] < 文件名或者设备名
选项
- -o 将文件拷贝打包成文件或者将文件输出到设备上
- -O filename 输出到指定的归档文件名
- -A 向已存在的归档文件中追加文件
- -i 解包,将打包文件解压或将设备上的备份还原到系统
- -I filename 对指定的归档文件名解压
- -t 预览,查看文件内容或者输出到设备上的文件内容
- -F filename 使用指定的文件名替代标准输入或输出
- -d 解包生成目录,在cpio还原时,自动的建立目录
-
-v 显示打包过程中的文件名
若不自宫,亦可练成