Shell进阶 文件查找 压缩打包
Shell脚本进阶 文件查找与打包压缩
1、变量
1.1 变量类型
变量类型:
- 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
- 用户自定义变量
1.2 Shell变量命名法则
- 不能使用程序中保留字:如 if,for
- 只能使用数字、字母及下划线,且不能以数字开头,不支持短横线 "-", 和主机名相反
- 见名知义,用英文单词命名,并体现出时间作用,不要用简写
- 统一命名规则: 驼峰命名法 studentname,大驼峰 StudentName 小驼峰 studentName
- 变量名大写:STUDENT_NAME
- 局部变量小写
- 函数名小写
变量赋值:
name='value'
value可以是以下多种形式
直接字串:name='root'变量引用:name="$USER"命令引用:Name=`COMMAND` 或 name=$(COMMAND)
1.3 位置变量
位置变量: bash shell中内置的变量,在脚本中通过命令行传递给脚本的参数
$1,$2,... 对应第1个,第2个等参数$0 命令本身,包括路径$* 传递脚本的所有参数,全部参数合为一个字符串$@ 传递脚本的所有参数,每个参数为独立字符串$# 传递给脚本的参数的个数 set -- 清空所有位置变量
范例:
[root@CentOS8 data]#cat arg.sh #!/bin/bashecho "1st arg is $1"echo "2st arg is $2"echo "3st arg is $3"echo "10st arg is ${10}"echo "11st arg is ${11}"echo "The number of arg is $#"echo "All args are $*"echo "All args are $@"echo "The scriptname is `basename $0`"[root@CentOS8 data]#bash arg.sh {a..z}1st arg is a2st arg is b3st arg is c10st arg is j11st arg is kThe number of arg is 26All args are a b c d e f g h i j k l m n o p q r s t u v w x y zAll args are a b c d e f g h i j k l m n o p q r s t u v w x y zThe scriptname is arg.sh
1.4 退出状态码
$?的值为0 #代表成功$?的值1-255 #代表失败
2、 条件测试命令
- test EXPRESSION
- [ EXPRESSION ] [ ] 和 test等价
- [[ EXPRESSION ]]
2.1 变量测试
#判断 NAME 变量是否定义[ -v NAME ]#判断 NAME 变量是否定义并且是名称引用[ -R NAME ]
2.2 数值测试
-eq 是否等于-ne 是否不等于-gt 是否大于-ge 是否大于等于-lt 是否小于-le 是否小于等于
2.3 字符串测试
-z STRING 字符串是否为空,没有定义或空为真,不空为假-n STRING 字符串是否不空,不空为真,空为假 STRING 同上STRING1 = STRING2 是否等于STRING1 != STRING2 是否不等于[[ ]] 建议当使用正则表达式或通配符使用,一般情况使用[]== 左侧字符串是否和右侧的PATTERN相同, PATTERN为通配符=~ 左侧字符串是否被右侧的正则表达式的PATTERN所匹配, PATTERN为扩展的正则表达式
2.4 文件测试
#存在性测试-a FILE 如果文件存在,则为True,同 -e-b FILE 如果FILE是块设备文件则为True。-c FILE 如果FILE是字符文件为True。-d FILE 如果FILE是目录则为True。-e FILE 如果文件存在,则为True。-f FILE 如果文件存在且为普通文件则为True。-h FILE 如果FILE是符号链接则为True。-L FILE 如果FILE是符号链接则为True。-p FILE 如果FILE是一个命名管道则为True。-S FILE 如果FILE是套接字,则为True。-k FILE 如果FILE设置了“sticky”位,则为True。-s FILE 如果文件存在且不为空,则为True。-t FD 如果在终端上打开FD,则为True。-u FILE 如果文件为set-user-id则为True。-r FILE 如果文件是可读的,则为True。-w FILE 如果文件是可写的,则为True。-x FILE 如果文件是可执行的,则为True。-O FILE 如果文件实际上属于您,则为True。-G FILE 如果文件实际上属于你的组,则为True。-N FILE 如果文件在上次读取后被修改过,则为True。FILE1 -nt FILE2 如果FILE1比FILE2更新则为True(根据修改日期)。FILE1 -ot FILE2 如果FILE1比FILE2老,则FILE2为True。FILE1 -ef FILE2 如果FILE1是FILE2的硬链接,则FILE2为True
2.5 ( ) 和 { }
(CMD1;CMD2;...) 和 { CMD1;CMD2;...;} 都可以将多个命令组合在一起,批量执行
(list) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境
{list;} 不会开启子shell,在当前shell中运行,会影响当前shell环境
2.6 使用read命令来接受输入
使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变量,所有剩余单词都被分配给最后一个变量,如果变量没有指定,默认标准输入的值赋值给系统内置变量REPLY
常见选项:
-p 指定要显示的提示-s 静默输入,一般用于密码-n N 指定输入的字符长度N-d '字符' 输入结束符-t N TIMEOUT为N秒
3、流程控制
3.1 选择执行 if 语句
格式:
if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
单分支
if 判断条件; then 条件为真的分支脚本fi
双分支
if 判断条件; then 条件为真的分支代码else 条件为假的分支代码fi
多分支
if 判断条件1; then 条件1为真的分支代码elif 判断条件2; then 条件2为真的分支代码elif 判断条件3; then 条件3为真的分支代码...else 以上条件都为假的分支代码fi
3.2 条件判断 case 语句
格式:
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
case 变量引用 inPAT1) 分支1 ;;PAT2) 分支2 ;;...*) 默认分支 ;;esac
4、循环
4.1 for 循环
格式1:
for NAME [in WORDS ... ]; do COMMANDS; donefor 变量名 in 列表;do 循环体done
格式2:
双小括号法,即((...))格式,可以用于算术运算
for ((: for (( exp1;exp2;exp3 )); do COMMANDS; done for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do 循环体 done
4.2 while 循环
while COMMANDS; do COMMANDS;donewhile CONDITION; do 循环体done
说明:
CONDITION: 循环控制条件;进入循环前,先做一次判断,每一次循环之后会再次做判断;条件为真,则执行一次循环;直到条件为"false"终止循环。
4.3 until 循环
until COMMANDS; do COMMANDS; doneuntil CONDITION; do 循环体done进入条件: CONDITION 为 false退出条件: CONDITION 为 ture
4.4 循环控制语句 continue
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断,最内层为第1层
while CONDITION1; do CMD1 ... if CONDITON2; then continue fi CMD ...done
范例:
[root@CentOS8 scripts]#cat continue_for.sh #!/bin/bashfor ((i=0;i<10;i++)); do for((j=0;j<10;j++)); do [ $j -eq 5 ] && continue 2 echo $j done echodone [root@CentOS8 scripts]#bash continue_for.sh 012340123401234
4.5 循环控制语句 break
break [N]:提前结束第N层的整个循环,最内层为第1层
while CONDITION1; do CMD1 ... if CONDITON2; then break fi CMD ...done
范例:
[root@CentOS8 scripts]#cat break_for.sh #!/bin/bashfor ((i=0;i<10;i++)); do for((j=0;j<10;j++));do [ $j -eq 5 ] && break 2 echo $j done echodone [root@CentOS8 scripts]#bash break_for.sh 01234[root@CentOS8 scripts]#
5、函数
5.1 定义函数
#语法1:func_name () { ...函数体...}#语法2:function func_name { ...函数体...}#语法3:function func_name () { ...函数体...}
5.2 查看函数
#查看当前已定义的函数名declare -f func_name#查看当前已定义的函数名定义declaer -F func_name#删除函数unset func_name
5.3 函数调用
函数的调用方式
- 可在交互式环境下定义函数
- 可将函数放在脚本文件中作为脚本的一部分
- 可放在只包含函数的单独文件中
5.3.1 交互式环境调用函数
[root@CentOS8 scripts]#dir () {> ls -l> }[root@CentOS8 scripts]#dirtotal 12-rw-r--r--. 1 root root 243 Mar 8 20:30 arg.sh
5.3.2 在脚本中定义及使用函数
函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用,调用函数使用函数名即可。
[root@CentOS8 scripts]#cat func1.sh #!/bin/bash#name:func1hello(){ echo "Hello there today's date is `date +%F`"}echo "now going to the function hello"helloecho "back from the function"[root@CentOS8 scripts]#bash func1.sh now going to the function helloHello there today's date is 2021-03-08back from the function
5.3.3 使用函数文件
可以将常使用的函数存入一个单独的函数文件,然后将函数载入shell,再进行函数调用
文件名可任意定义,但最好与相关任务有某种类型。
一旦函数文件载入shell,就可以在命令行或脚本中调用函数,可以使用delcare -f 或 set 命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数
若要改动函数,首先用unset命令从shell中删除函数,改动完毕后,再重新载入此文件
实现函数文件的过程:
- 创建函数文件,只存放函数的定义
- 在shell脚本或交互式shell中调用函数文件,格式如下:
. filename 或 source filename
6、脚本进阶实例
- 编写脚本 createuser.sh,实现如下功能:使用一个用户名做为参数,如果 指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息
[root@CentOS8 scripts]#cat createuser.sh #!/bin/bashread -p "请输入一个用户名:" NAMEif `id $NAME &> /dev/null`;then echo "$NAME已存在,id信息为: `id $NAME`"else PASSWD=`cat /dev/urandom |tr -cd [:alpha:] |head -c8` `useradd $NAME &> /dev/null` `echo "$PASSWD" |passwd --stdin $NAME &> /dev/null` echo "用户名:$NAME 密码:$PASSWD" >> /data/user.txt `chage -d 0 $NAME` echo "$NAME已添加,id信息为:`id $NAME` 密码为:$PASSWD" fi[root@CentOS8 scripts]#bash createuser.sh请输入一个用户名:graingrain已添加,id信息为:uid=1001(grain) gid=1001(grain) groups=1001(grain) 密码为:NodUrJyB[root@CentOS8 scripts]#bash createuser.sh请输入一个用户名:graingrain已存在,id信息为: uid=1001(grain) gid=1001(grain) groups=1001(grain)
- 编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等
vim /etc/vimrcset cul set ts=4set pasteset autoindentautocmd 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: grain") call setline(5,"#TIM: 37xxxxxx") call setline(6,"#Email: 37xxxxxx@qq.com") call setline(7,"#Date: ".strftime("%Y-%m-%d")) call setline(8,"#FileName: ".expand("%")) call setline(9,"#Version: 1.0") call setline(10,"#Description: The New Script") call setline(11,"#Copyright (C): ".strftime("%Y")." All rights reserved") call setline(12,"#***********************************************************") call setline(13,"") endifendfunc
7、文件查找
文件查找:locate、find
非实时查找(数据库查找):locate
实时查找:find
7.1 locate
locate 查询系统上预建的文件索引数据库/var/lib/locate/mlocate.db
索引构建过程需要遍历整个根文件系统,很消耗资源,执行update可以更新数据库
工作特点:
- 查找速度快
- 模糊查找
- 非实时查找
- 搜索的是文件的全路径,不仅仅是文件名
- 可能只搜索用户具备读取和执行权限的目录
格式:
locate [OPTION]...[PATTERN]...
常用选项
-i 不区分大小写搜索-r 使用基本正则表达式-n N 只列举前N个匹配项目
7.2 find
find是事实查找工具,通过遍历指定路径完成文件查找
工作特点:
- 查找速度略慢
- 精确查找
- 实时查找
- 查找条件丰富
- 可能只搜索用户具备读取和执行权限的目录
格式:
find [OPTION]...[查找路径][查找条件][处理动作]
7.2.1 指定搜索目录层级
-maxdepth level 最大搜索目录深度-mindepth level 最小搜索目录深度-depth -d 对每个目录先处理目录内文件,再处理目录本身find /etc -maxdepth 2 -mindepth 2
7.2.2 根据文件名和inode查找
-name #文件名称,支持glob通配符-iname #文件名称,不区分大小写-inum n #按inode号查找-samefile name #相同inode号的文件-links n #链接数为n的文件-regex "PATTERN" 以PATTERN匹配整个文件路径,非文件名称
7.2.3 根据属主、属组查找
-user username:查找属主为指定用户的文件-group grpname: 查找属组为指定组的文件-uid uid:查找属主为指定uid号的文件-gid gid:查找属组为指定gid号的文件-nouser:查找没有属主的文件-nogroup:查找没有属组的文件
7.2.4 根据文件类型查找
-type TYPE可以是以下类型:f: 普通文件d: 目录文件l: 符号链接文件s: 套接字文件b: 块设备文件c: 字符设备文件p: 管道文件-empty 空文件或目录-path 排除目录find /data -type d -empty#查找/etc/下,除/etc/sane.d目录的其它所有.conf后缀的文件find /etc -path '/etc/sane.d' -a prune -o -name "*.conf"
7.2.5 组合条件
-a 与,默认多个条件是与关系-o 或-not 非 !#查找/tmp目录下,属组不是root,且文件名不以f开头的文件find /tmp ( -not -user root -a -not -name 'f*' )-ls
7.2.6 根据文件大小查找
-size [+|-]#UNIT 常用单位:k, M, G, C(byte),大小写敏感#UNIT: (#-1,#] 如:6k 表示(5k,6k]-#UNIT: [0,#-1] 如:-6k 表示[0,5k]+#UNIT: (#,∞) 如:+6k 表示(6k,∞)find / -size +10G
7.2.7 根据时间戳
以"天"为单位-atime [+|-]# #: [#,#+1) +#: [#+1,∞] -#:[0,#)-mtime-ctime以"分钟"为单位-amin-mmin-cmin
7.2.8 根据权限查找
-perm [/|-] MODEMODE: 精确权限匹配/MODE: u,g,o有一个匹配即可,或关系-MODE: u,g,o每个人都拥有指定权限才匹配,与关系0 表示不关注
7.2.9 处理动作
-print:默认的处理动作,显示至屏幕-ls: 类似对找到的文件执行 ls -l命令-fls file:查找到的所有长格式信息保存到指定文件中,相当于 -ls > file-delete: 删除查找到的文件-ok COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令,对每个文件执行命令前,都会交互式要求用户确认-exec COMMAND {} \; 对查找到的每个文件执行由COMMAND指定的命令{}: 用于引用查找到的文件名称自身#查找/data下权限为644,后缀为sh的普通文件,增加执行权限find /data -type f -perm 644 -name "*.sh" -exec chmod 755 {} \;
7.3 参数替换 xargs
xargs用于产生某个命令的参数,可以读入stdin的数据,并且以空格符或回车符将stdin的数据分割成为参数
find 和 xargs 的组合
find | xargs COMMAND#批量创建和删除用户echo user{1..10} | xargs -n1 useraddecho user{1..10} | xargs -n1 userdel -r
8、 压缩和解压缩
8.1 compress 和 uncompress
格式
compress options [file...]uncompress file.z #解压缩-d 解压缩,相当于uncompress-c 结果输出至标准输出,不删除原文件-v 显示详情bzat file.z 不显示解压缩的前提下查看文本文件内容
8.2 gzip 和 gunzip
常用选项
gzip [option]... file ...-d 解压缩,相当于gunzip-c 结果输出至标准输出,不删除原文件-# 指定压缩比,#取值为1-9,值越大压缩比越大
8.3 bzip2 和 bunzip2
bzip2 [option]... file ...-d 解压缩,相当于bunzip2-c 结果输出至标准输出,不删除原文件-# 指定压缩比,#取值为1-9,默认为9-k keep,保留原文件
8.4 xz 和 unxz
xz [option]... file ...-k keep,保留原文件-d 解压缩-c 结果输出至标准输出,保留原文件不改变-# 压缩比,取值1-9,默认为6
一般压缩率 compress < gzip < bzip2 < xz ,但压缩率越高,消耗的系统资源越大,同时4个工具都只能压缩文件。
8.5 zip 和 unzip
zip可以实现打包目录和多个文件成一个文件并压缩,但可能会丢失文件属性信息。一般使用tar代替。
9、打包和解包
9.1 tar
tar可以对目录和多个文件打包成一个文件并压缩,保留文件属性不丢失。
tar [option]...#打包归档,保留权限tar -cvf /PATH/FILE.tar FILE...#追加文件至归档tar -rf /PATH/FILE.tar FILE...#解包归档tar xf /PATH/FILE.tartar xf /PATH/FILE.tar -C /data
9.2 查找打包实例
- 查找/etc目录下大于1M且类型为普通文件的所有文件
find /etc -size +1M -type f -ls
- 打包/etc/目录下面所有conf结尾的文件,压缩包名称为当天的时间,并拷贝到/usr/local/src目录备份
[root@CentOS8 scripts]#find /etc/ -name "*.conf"|xargs tar -cvf /usr/local/src/`date +%F`.tar.gz[root@CentOS8 scripts]#ls /usr/local/src/2021-03-10.tar.gz
- 查找当前系统上没有属主或属组,且最近一个周内曾被访问过的文件或目录
find / \( -nouser -o -nogroup \) -a -atime -7
- 查找/etc目录下至少有一类用户没有执行权限的文件
find /etc -not -perm /111
©著作权归作者所有:来自51CTO博客作者哀木缇的原创作品,如需转载,请注明出处,否则将追究法律责任
更多相关文章
- [灾备]通过 NAS 与文件服务器结合构建数据容灾系统
- PHP扩展知识:URL相关函数和api接口案例
- 笔记 | Python之函数式编程
- 小技巧 | 用python给敏感信息加水印
- 详解javascript的bind方法
- kubernetes常用控制器之Job和CronJob
- K8s手动方式搭建平台及问题汇总
- 一杯茶的功夫,上手Redis持久化机制
- 17、运维核心技能-Linux系统下用户权限管理,,200R