Shell脚本进阶 文件查找与打包压缩

1、变量

1.1 变量类型

变量类型:

  • 内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
  • 用户自定义变量

1.2 Shell变量命名法则

  1. 不能使用程序中保留字:如 if,for
  2. 只能使用数字、字母及下划线,且不能以数字开头,不支持短横线 "-", 和主机名相反
  3. 见名知义,用英文单词命名,并体现出时间作用,不要用简写
  4. 统一命名规则: 驼峰命名法 studentname,大驼峰 StudentName 小驼峰 studentName
  5. 变量名大写:STUDENT_NAME
  6. 局部变量小写
  7. 函数名小写

变量赋值

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中删除函数,改动完毕后,再重新载入此文件

实现函数文件的过程:

  1. 创建函数文件,只存放函数的定义
  2. 在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博客作者哀木缇的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. [灾备]通过 NAS 与文件服务器结合构建数据容灾系统
  2. PHP扩展知识:URL相关函数和api接口案例
  3. 笔记 | Python之函数式编程
  4. 小技巧 | 用python给敏感信息加水印
  5. 详解javascript的bind方法
  6. kubernetes常用控制器之Job和CronJob
  7. K8s手动方式搭建平台及问题汇总
  8. 一杯茶的功夫,上手Redis持久化机制
  9. 17、运维核心技能-Linux系统下用户权限管理,,200R

随机推荐

  1. [Android] 录音与播放录音实现
  2. android添加外部按键
  3. Android 中自定义View的应用
  4. Android spannableStringBuilder用法整理
  5. Android Menu功能菜单
  6. android 侧滑菜单DrawerLayout
  7. android command
  8. 在android中使用HttpURLConnection进行文
  9. 如何隐藏Android4.0及以上版本的ActionBa
  10. android获取设备存储信息