Shell进阶 文件查找 压缩打包

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/bash
echo "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 a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
The number of arg is 26
All 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 z
All 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 z
The 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 变量引用 in
PAT1)
    分支1
    ;;
PAT2)
    分支2
    ;;
...
*)
    默认分支
    ;;
esac

4、循环

4.1 for 循环

格式1:

for NAME [in WORDS ... ]; do COMMANDS; done

for 变量名 in 列表;do
    循环体
done

格式2:

双小括号法,即((...))格式,可以用于算术运算

for ((: for (( exp1;exp2;exp3 )); do COMMANDS; done
    for ((控制变量初始化;条件判断表达式;控制变量的修正表达式));
    do
        循环体
    done

4.2 while 循环

while COMMANDS; do COMMANDS;done

while CONDITION; do
        循环体
done

说明:

CONDITION: 循环控制条件;进入循环前,先做一次判断,每一次循环之后会再次做判断;条件为真,则执行一次循环;直到条件为"false"终止循环。

4.3 until 循环

until COMMANDS; do COMMANDS; done

until 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/bash
for ((i=0;i<10;i++)); do
    for((j=0;j<10;j++)); do
        [ $j -eq 5 ] && continue 2
         echo $j
    done
    echo
done    
[root@CentOS8 scripts]#bash continue_for.sh 
0
1
2
3
4
0
1
2
3
4
0
1
2
3
4

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/bash
for ((i=0;i<10;i++)); do
    for((j=0;j<10;j++));do
        [ $j -eq 5 ] && break 2
         echo $j
    done
    echo
done    
[root@CentOS8 scripts]#bash break_for.sh 
0
1
2
3
4
[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]#dir
total 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:func1
hello(){
    echo "Hello there today‘s date is `date +%F`"
}
echo "now going to the function hello"
hello
echo "back from the function"
[root@CentOS8 scripts]#bash func1.sh 
now going to the function hello
Hello there today‘s date is 2021-03-08
back 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/bash
read -p "请输入一个用户名:" NAME
if `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
请输入一个用户名:grain
grain已添加,id信息为:uid=1001(grain) gid=1001(grain) groups=1001(grain) 密码为:NodUrJyB
[root@CentOS8 scripts]#bash createuser.sh
请输入一个用户名:grain
grain已存在,id信息为: uid=1001(grain) gid=1001(grain) groups=1001(grain)
  • 编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等
vim /etc/vimrc
set cul 
set ts=4
set paste
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:            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,"")
    endif
endfunc

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

Shell进阶 文件查找 压缩打包

7.2.8 根据权限查找

-perm [/|-] MODE

MODE: 精确权限匹配
/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 useradd
echo 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.tar
tar 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

Shell进阶 文件查找 压缩打包

上一篇:shell操作典型案例--FTP操作


下一篇:Linux环境jmeter安装文档