• shell脚本耕升(一)



    篇幅较长,可能还有后续更新,建议收藏
    此篇是我读《 linux shell 脚本攻略》所写的的个人笔记
    文章主体脉络由书中得来
    相关命令用法由书中或互联网或系统帮助,或个人实验得来
    例子由自己编写而来

    我为什么都标个人原创?

    1.本人所有文章都是个人笔记,不是专业写博客的
    2.此文章不产生任何盈利,与原书也发生不了任何纠纷
    3.例子,命令用法,注释都是个人编写
    4.例如此书,转载必须填写原网址,我该如何填写一本书的网址?
    5.文章内容可能从一篇,或者很多篇博客,书籍,又或者是系统命令帮助而来,我没有很多精力来记录他们,或者询问能否转载

    写博客的意义
    1.所有文章只是作为个人在线笔记
    2.投公开发表是觉得可能会对初学者提供一些帮助

    文件描述符

    文件描述符是与一个打开的文件或数据流相关联的整数。也是用于访问文件的一个抽象指针。存取文件离不开被称为“文件描述符”的特殊数字。0、1和2分别是stdin、stdout和stderr的预留描述符。

    • 0——stdin(标准输人)
    • 1——stdout(标准输出)
    • 2——stderr(标准错误)

    例如我们在源码安装mysql初始化的时候会有密码需要暂时保存一下那我们可以使用echo将输出文本重定向到一个文件中

    [root@zzyyssxx ~]# echo '123456' > pwd.txt
    [root@zzyyssxx ~]# cat pwd.txt 
    123456
    [root@zzyyssxx ~]# echo 'abcdef' >>  pwd.txt
    [root@zzyyssxx ~]# cat pwd.txt 
    123456
    abcdef
    [root@zzyyssxx ~]# echo '2233' >  pwd.txt
    [root@zzyyssxx ~]# cat pwd.txt 
    2233
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    和>>并不相同。尽管这两个操作符都可以将文本重定向到文件,但是前者会先清空文件,再写入内容;而后者会将内容追加到现有文件的下一行。

    当使用重定向操作符时,重定向的内容不会出现在终端,而是直接被导入文件。重定向操作符默认使用标准输出。如果想使用特定的文件描述符,你必须将描述符置于操作符之前。

    相同的 > 等同于 1> ,>> 等同于 1>>

    输入错误命令时会出现错误信息,同时会返回一个非0状态码

    [root@zzyyssxx ~]# lshdfsjf
    -bash: lshdfsjf: 未找到命令
    
    • 1
    • 2

    这里我们输入一个不合规参数,会返回标准错误信息

    [root@zzyyssxx ~]# ls +
    ls: 无法访问+: 没有那个文件或目录
    [root@zzyyssxx ~]# echo $?
    2
    
    • 1
    • 2
    • 3
    • 4
    [root@zzyyssxx ~]# ls + > out.txt
    ls: 无法访问+: 没有那个文件或目录
    [root@zzyyssxx ~]# cat out.txt 
    [root@zzyyssxx ~]# ls + 2> out.txt
    [root@zzyyssxx ~]# cat out.txt 
    ls: 无法访问+: 没有那个文件或目录
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    显然的标准输出没有被写到文件里,标准错误被写到了文件里面

    也可以将错误和输出重定向到不同的文件

    cmd 2>stderr.txt 1>stdout.txt
    
    • 1

    也可以将stderr转换成stdout,然后重定向到一个文件中

    cmd 2>&1 output.txt
    或 cmd &> output.txt
    
    • 1
    • 2

    当我们不想看到错误的输出时可以

    cmd 2> /dev/null
    
    • 1

    dev/null是一个特殊的设备文件,这个文件接收到的任何数据都会被丢弃。因此,null设备通常也被称为黑洞。

    当对stderr或stdout进行重定向时,重定向的文本将传入文件。因为文本已经被重定向到文件中,也就没剩下什么东西可以通过管道(I)传给接下来的命令,而这些命令是通过stdin来接收文本的。。

    tee命令可以一方面将数据重定向到文件,另一方面还可以提供一份重定向的数据副本作为后续命令的stdin

    作用:从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件
    
    语法格式:tee [参数] [文件]
    
    常用参数:
    
    -a	附加到既有文件的后面,而非覆盖它
    -i	忽略中断信号
    — help 	查看帮助信息
    — version	显示版本信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    [root@zzyyssxx ~]# echo '123' | tee 1.txt 2.txt
    123
    [root@zzyyssxx ~]# ls
    1.txt  2.txt 
    [root@zzyyssxx ~]# cat 1.txt 
    123
    [root@zzyyssxx ~]# cat 2.txt 
    123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    有时候,我们需要对文本块(多行文本)像标准输人一样进行重定向。考虑一个特殊情况:文本就位于shell脚本中。可以按照下面的方法成:

    [root@zzyyssxx ~]# cat < 123.txt
    > 1
    > 2
    > 3
    > EOF
    [root@zzyyssxx ~]# ls
    123.txt
    [root@zzyyssxx ~]# cat 123.txt 
    1
    2
    3
    [root@zzyyssxx ~]# cat 1.sh 
    #!/bin/bash
    
    cat < 111.txt
    a
    b
    c
    EOF
     
    [root@zzyyssxx ~]# chmod +x 1.sh  #授权
    [root@zzyyssxx ~]# ls
    123.txt  1.sh
    [root@zzyyssxx ~]# ./1.sh   #执行
    [root@zzyyssxx ~]# ls
    111.txt  123.txt  1.sh
    [root@zzyyssxx ~]# cat 111.txt 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    自定义文件描述符

    除了预留的0,1,2描述符,我们可以使用exec命令创建自定义的文件描述符。文件的打开模式通常来说,会使用3种模式。

    • 只读模式
    • 截断模式
    • 追加模式

    exec命令用于调用并执行指定的命令,也可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端。

    语法格式:exec [参数]
    
    常用参数:
    
    -c	在空环境中执行指定的命令
    
    • 1
    • 2
    • 3
    • 4
    • 5
    [root@zzyyssxx ~]# exec 3<111.txt  #使用文件描述符3打开并读取文件
    [root@zzyyssxx ~]# cat <&3
    a
    b
    c
    //如果要再次读取就不能,需要再次通过exec重新分配文件扫描符
    [root@zzyyssxx ~]# cat <&3
    
    //与find连用
    [root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ls {} \;
    /root/123.txt
    /root/111.txt
    //需要注意的是连用的时候要输入完整的命令
    [root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ll {} \;
    find: ‘ll’: 没有那个文件或目录
    find: ‘ll’: 没有那个文件或目录
    [root@zzyyssxx ~]# find /root/ -name "*.txt" -exec ls -l {} \;
    -rw-r--r-- 1 root root 6 4月  12 13:58 /root/123.txt
    -rw-r--r-- 1 root root 6 4月  12 14:04 /root/111.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    创建一个文件描述符用于写入(截断模式)

    [root@zzyyssxx ~]# cat <&3
    [root@zzyyssxx ~]# exec 3>111.txt 
    [root@zzyyssxx ~]# cat 111.txt 
    [root@zzyyssxx ~]# echo new >&3
    [root@zzyyssxx ~]# cat 111.txt 
    new
    [root@zzyyssxx ~]# exec 4>>111.txt
    [root@zzyyssxx ~]# echo 110 >&4    
    [root@zzyyssxx ~]# cat 111.txt 
    new
    old
    110
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    数组和关联数组

    数组是shell脚本重要的组成部分,它借助索引将多个独立数据存储为1个集合。

    Bash同时支持普通数组和关联数组。普通数组只能使用整数作为数组索引
    ,而关联数组可以使用字符串作为数组索引。关联数组在很多操作中相当有用。Bash从4.0版本开始支持关联数组。

    可以使用一列值定义一个数组,#这些值将会存储在以0为起始索引的连续位置上

    [root@zzyyssxx ~]# array_var=(1 2 3 4 5)
    [root@zzyyssxx ~]# echo ${array_var[0]}
    1
    
    • 1
    • 2
    • 3

    另外,还可以将数组定义成一组索引-值

    [root@zzyyssxx ~]# array_var[0]="a"
    [root@zzyyssxx ~]# array_var[1]="b"
    [root@zzyyssxx ~]# array_var[2]="c"
    [root@zzyyssxx ~]# echo $array_var[2]  //不加括号会默认打印第一个索引的值
    a[2]
    [root@zzyyssxx ~]# echo ${array_var[2]}
    c
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以清单形式打印数组中所有值

    [root@zzyyssxx ~]# echo ${array_var[*]}
    a b c
    [root@zzyyssxx ~]# echo ${array_var[@]}
    a b c
    
    • 1
    • 2
    • 3
    • 4

    打印数组长度,也就是元素个数

    [root@zzyyssxx ~]# echo ${#array_var[@]}
    3
    [root@zzyyssxx ~]# echo ${#array_var[*]}
    3
    
    • 1
    • 2
    • 3
    • 4

    定义关联数组

    在关联数组中,我们可以用任意的文本作为数组索引。而在普通数组中,只能用整数作为数组索引。关联数组需要先声明再使用。
    首先,需要使用单独的声明语句将一个变量名声明为关联数组。声明语句如下:

    [root@zzyyssxx ~]# declare -A acb_array
    
    • 1
    语法格式: declare [参数] [目录]
    
    declare: 用法:declare [-aAfFgilrtux] [-p] [name[=value] ...]
    
    常用参数:
    
    -a	声明数组变量
    -f	仅显示函数
    -F	不显示函数定义
    -i	先计算表达式,把结果赋给所声明变量
    -p	显示给定变量的定义的方法和值,当使用此选项时,其他的选项将被忽略
    -r	定义只读变量
    -x	将指定的Shell变量转换成环境变量
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    [root@zzyyssxx ~]# declare 
    BASH=/bin/bash
    BASHOPTS=checkwinsize:cmdhist:expand_aliases:extquote:force_fignore:histappend:hostcomplete:interactive_comments:login_shell:progcomp:promptvars:sourcepath
    BASH_ALIASES=()
    BASH_ARGC=()
    BASH_ARGV=()
    BASH_CMDS=()
    BASH_LINENO=()
    BASH_SOURCE=()
    BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
    BASH_VERSION='4.2.46(2)-release'
    CALSS_PATH=.:/usr/local/jdk1.8.0_221/lib/dt.jar:/usr/local/jdk1.8.0_221/lib/tools.jar:/usr/local/jdk1.8.0_221/jre/lib
    COLUMNS=83
    DIRSTACK=()
    EUID=0
    GROUPS=()
    HISTCONTROL=ignoredups
    HISTFILE=/root/.bash_history
    HISTFILESIZE=1000
    HISTSIZE=1000
    HOME=/root
    HOSTNAME=zzyyssxx
    HOSTTYPE=x86_64
    ID=0
    IFS=$' \t\n'
    JAVA_HOME=/usr/local/jdk1.8.0_221
    ......
    USER=root
    XDG_RUNTIME_DIR=/run/user/0
    XDG_SESSION_ID=4097
    _=-h
    acb_array=()
    array_var=([0]="a" [1]="b" [2]="c")
    colors=/root/.dircolors
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    可以看到里面包含许多环境变量

    [root@zzyyssxx ~]# declare -p SSH_CLIENT //这是ssh相关参数
    declare -x SSH_CLIENT="39.170.63.135 58535 22"
    [root@zzyyssxx ~]# echo $SSH_CLIENT
    39.170.63.135 58535 22
    
    • 1
    • 2
    • 3
    • 4

    篇幅有限,此处不过多描述

    可以用两种方法将元素添加到关联数组中。

    • 1.用内嵌索引-值列表法,写一个索引-值列表:
    [root@zzyyssxx ~]# acb_array=([index1]=jerry [index2]=tom)
    
    • 1
    • 2.使用独立的索引-值进行赋值:
    [root@zzyyssxx ~]# acb_array[ind1]=apple
    [root@zzyyssxx ~]# acb_array[ind2]=orange
    [root@zzyyssxx ~]# echo ${acb_array[ind2]}
    orange
    [root@zzyyssxx ~]# echo ${acb_array[ind1]}
    apple
    [root@zzyyssxx ~]# echo ${acb_array[0]} //直接打印索引0这里为空
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    每一个数组元素都有一个索引用于查找。普通数组和关联数组具有不同的索引类型。

    //列出数组索引
    [root@zzyyssxx ~]# echo ${!acb_array[*]}
    index1 index2 ind1 ind2
    [root@zzyyssxx ~]# echo ${!acb_array[@]}
    index1 index2 ind1 ind2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    别名

    alias命令用来设置指令的别名。我们可以使用该命令可以将一些较长的命令进行简化。使用alias时,用户必须使用单引号 ‘ ‘ 将原来的命令引起来,防止特殊字符导致错误。

    语法格式:alias [参数]
    
    常用参数:
    
    -p	打印已经设置的命令别名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    [root@zzyyssxx ~]# alias -p
    alias cp='cp -i'
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias mv='mv -i'
    alias rm='rm -i'
    alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
    
    [root@zzyyssxx ~]# alias cd='cd $@;ls --color=auto' //添加别名
    [root@zzyyssxx ~]# alias -p
    alias cd='cd ;ls --color=auto'  //新添加的别名
    alias cp='cp -i'
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l.='ls -d .* --color=auto'
    alias ll='ls -l --color=auto'
    alias ls='ls --color=auto'
    alias mv='mv -i'
    alias rm='rm -i'
    alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
    
    //测试一下
    [root@zzyyssxx ~]# cd /usr/local/
    aegis         games                       lib      sbin
    bin           include                     lib64    share
    cloudmonitor  jdk1.8.0_221                libexec  src
    etc           jdk-8u221-linux-x64.tar.gz  nginx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    alias命令的作用只是暂时的。一旦关闭当前终端,所有设置过的别名就失效了。为了使别名设置一直保持作用,可以将它放入~.bashrc文件中。因为每当一个新的shell进程生成时,都会执行 ~/.bashr中的命令。

    [root@zzyyssxx ~]# echo 'alias cd="cd $@;ls --color=auto"' >> ~/.bashrc  //新进程也同样生效
    
    • 1

    如果需要删除别名,只用将其对应的语句从~l.bashrc中删除,或者使用unalias命令。另一种创建别名的方法是定义一个具有新名称的函数,并把它写入 ~/.bashr

    [root@zzyyssxx ~]#  alias rm='cp $@ ~/backup; rm $@'
    
    • 1

    这样写可以防止误操作,定期清理即可
    当你创建别名时,如果已经有同名的别名存在,那么原有的别名设置将被新的取代。

    别名也存在相关安全隐患,万一服务器被入侵常用命令修改为其他命令会造成巨大损失,轻则提桶跑路,重则背上法律责任。
    那么,如果避免这一点呢,答案就是转义

    [root@zzyyssxx ~]# cd /usr/local/
    aegis         games                       lib      sbin
    bin           include                     lib64    share
    cloudmonitor  jdk1.8.0_221                libexec  src
    etc           jdk-8u221-linux-x64.tar.gz  nginx
    [root@zzyyssxx ~]# \cd /usr/local/
    [root@zzyyssxx local]# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    字符\对命令实施转义,使我们可以执行原本的命令,而不是这些命令的别名替身。

    获取终端信息

    编写命令行shell脚本的时候,总是免不了大量处理当前终端的相关信息,
    比如行数、列数、光标位置和遮盖密码字段等。

    put命令将通过 terminfo 数据库对您的终端会话进行初始化和操作。通过使用 tput,您可以更改几项终端功能,如移动或更改光标、更改文本属性,以及清除终端屏幕的特定区域。

    语法格式:tput [参数]

    setb 用于设置背景颜色
    setf 用于设置前景颜色
    cols 获取行数
    lines 获取列数

    获取,设置日期与延时

    当我们备份数据库时一般需要根据日期以及时间来执行操作。而延时一般在监控任务脚本,比如每5秒执行一次脚本。

    我们能够以多种格式打印日期,也可以在命令行中设置日期。在类UNIX系统中,日期被存储为一个整数,其大小为自世界标准时间1970年1月1日0时0分0秒起所流逝的秒数。这种计时方式称之为纪元时或UNIX时间,一般叫时间戳。


    读取日期

    [root@zzyyssxx ~]# date
    20220418日 星期一 09:17:16 CST
    [root@zzyyssxx ~]# date +%s
    1650244686
    
    • 1
    • 2
    • 3
    • 4

    将得到的时间戳进行转换,因为用的是云主机所以不用校准时间

    //输出给定日期的字符串
    [root@zzyyssxx ~]# date --date "Jan 20 2010" +%A
    星期三
    [root@zzyyssxx ~]# date "+%d %B %Y"
    18 四月 2022
    [root@zzyyssxx ~]# date "+%Y %B %d"
    2022 四月 18
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    类似的这样的脚本可以检查一组命令花费的时间

    #!/bin/bash
    
    start=$(date +%s)
    commands;
    end=$(date +%s)
        
    difference=$(( end -start ))
    
    echo time is $difference seconds
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    延时

    编写以循环的方式监控脚本时,需要设置时间间隔,可以利用sleep来延时

    [root@zzyyssxx ~]# cat test.sh 
    #!/bin/bash
    echo -n count:
    tput sc
    count=0;
    while true;
    do
    if [ $count -lt 30 ];then
    let count++;
    sleep 1;
    tput rc
    tput ed
    echo -n $count;
    else exit 0;
    fi
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    变量count初始化为0,随后每循环一次便增加1。echo语句打印出count的值。我们用tput sc存储光标位置。在每次循环中,我们通过恢复之前存储的光标位置,在终端中打印出新的count值。恢复光标位置的命令是tput rc。tptit ed清除从当前光标位置到行尾之间的所有内容,使得旧的count值可以被清除并写人新值。循环内的1秒钟延时是通过sleep命令来实现的

    调试脚本

    调试功能是每一种编程语言都应该实现的重要特性之一,当出现一些始料未及的情况时,用它来生成脚本运行信息。调试信息可以帮你弄清楚是什么原因使得程序发生崩溃或行为异常。

    //
    [root@zzyyssxx ~]# sh -x test.sh 
    。。。。。。。略
    + echo -n 29
    29+ true
    + '[' 29 -lt 30 ']'
    + let count++
    + sleep 1
    + tput rc
    + tput ed
    + echo -n 30
    30+ true
    + '[' 30 -lt 30 ']'
    + exit 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    -x 将脚本中执行过的每一行都输出到stdout,当我们只关注脚本某些命令可以使用调试打印。

    set -x:在执行时显示参数和命令
    set +:禁止调试
    set -v:当命令进行读取时显示输入
    set +v:禁止打印输入
    
    • 1
    • 2
    • 3
    • 4
    [root@zzyyssxx ~]# cat debug.sh 
    #!/bin/bash
    
    for i in {1..6}
    do
    set -x
    echo $i
    set +x
    done
    
    echo "script executed"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    [root@zzyyssxx ~]# sh -x debug.sh 
    + for i in '{1..6}'
    + set -x
    + echo 1
    1
    + set +x
    + echo 2
    2
    + set +x
    + echo 3
    3
    + set +x
    + echo 4
    4
    + set +x
    + echo 5
    5
    + set +x
    + echo 6
    6
    + set +x
    script executed
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    也可以利用shebang来调试,将#!/bin/bash变为 #!/bin/bash -xv

    #!/bin/bash -xv
    
    for i in {1..6}
    do
    set -x
    echo $i
    set +x
    done
    
    echo "script executed"
    
    [root@zzyyssxx ~]# chmod +x debug.sh 
    [root@zzyyssxx ~]# ./debug.sh 
    #!/bin/bash -xv
    
    for i in {1..6}
    do
    set -x
    echo $i
    set +x
    done
    + for i in '{1..6}'
    + set -x
    + echo 1
    1
    + set +x
    + echo 2
    2
    + set +x
    + echo 3
    3
    + set +x
    + echo 4
    4
    + set +x
    + echo 5
    5
    + set +x
    + echo 6
    6
    + set +x
    
    echo "script executed"
    script executed
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    函数与参数

    定义函数:

    function  函数名 ()
    {
    命令;
    流程语句;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    函数名 ()
    {
    命令;
    流程语句;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    定义完函数后只需要使用函数名就可以调用某个函数

    函数名 ;//调用函数
    
    • 1

    参数可以传递给函数,并由脚本进行访问

    函数名 arg1 arg2//传递参数
    
    • 1
    fname ( )
    {
    echo $1, $2 ;       #访问参数1和参数2
    echo " $@";       #以列表的方式一次性打印所有参数
    echo "$*";          #类似于$0,但是参数被作为单个实体
    return 0 ;           #返回值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    参数可以传递给脚本并通过script :$0(脚本名)访问
    $1是第一个参数。

    $2是第二个参数。

    $n是第n个参数。

    “$@”被扩展成”$1" “$2” "$3"等。

    "$”被扩展成"$1c$2c 3 " " 3" " 3""@”用得最多。由于"$"将所有的参数当做单个字符串,因此它很少被使用。

    递归函数

    在Bash中,函数同样支持递归(可以调用自身的函数)。例如,F( ) { echo $1; F hello;sleep 1; }。

    • Fork炸弹
    :() { :|:& }; :
    
    • 1

    这个递归函数能够调用自身,不断地生成新的进程,最终造成拒绝式服务攻击(Dos)。函数调用前的&将子进程放入后台。因为这段代码会分支出大量的进程,所以被称为Fork炸弹。

    http://en.wikipedia.org/wiki/Fork_bomb fork炸弹相关解释

    可以通过ulimit -u 20来限制用户进程数量
    永久生效可以

    echo   '"用户名" - nproc 20 ' >> /etc/security/limits.conf
    
    • 1

    导出函数

    函数也能像环境变量一样用export导出,这样一来函数的作用域就可以扩展到子进程中。

    export -f 函数名

    读取命令序列输出

    shell脚本可以轻松地将多个命令或工具组合起来生成输出。一个命令的输出可以作为另一个命令的输入,而这个命令的输出又会传递至另一个命令。

    [root@localhost ~]# ls
    anaconda-ks.cfg  nmap-7.92-1.x86_64.rpm
    [root@localhost ~]# ls | cat -n   		## 管道符|将前一个命令的参数传给下一个命令
         1  anaconda-ks.cfg
         2  nmap-7.92-1.x86_64.rpm
    [root@localhost ~]# ls | cat -n > out.txt
    [root@localhost ~]# ls 
    anaconda-ks.cfg  nmap-7.92-1.x86_64.rpm  out.txt
    [root@localhost ~]# cat out.txt 
         1  anaconda-ks.cfg
         2  nmap-7.92-1.x86_64.rpm
         3  out.txt
    
    ##子shell
    [root@localhost ~]# ouput=$(ls | cat -n)
    [root@localhost ~]# echo $ouput
    1 123.txt 2 anaconda-ks.cfg 3 nmap-7.92-1.x86_64.rpm 4 out.txt
    
    ##反引用`在tab键上面
    [root@localhost ~]# ouput=`ls | cat`
    [root@localhost ~]# echo $ouput
    123.txt anaconda-ks.cfg nmap-7.92-1.x86_64.rpm out.txt
    
    ##加双引号保留换行符
    [root@localhost ~]# abc=$(ls | cat -n)
    [root@localhost ~]# echo "$abc"
         1  123
         2  123.txt
         3  anaconda-ks.cfg
         4  nmap-7.92-1.x86_64.rpm
         5  out.txt
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    不按回车键的方式读取字符“n”

    read命令的功能是用于读取单行数据内容,一般是从标准输入中读取数值,用于给变量赋值。

    |语法格式:read [参数]

    常用参数:说明
    -a定义一个数组,以空格为间隔符进行赋值
    -d定义一个结束标志
    -p设置提示信息
    -e在输入的时候可以使用命令补全功能
    -n定义输入文本的长度
    -r禁用转义符(\)
    -s输入字符不在屏幕显示
    -t限定最长等待时间
    -u从文件描述符中读入信息
    [root@localhost ~]# read -n 2 asd  #-n指定2个字符, 输入2个字符后会自动回车
    23[root@localhost ~]# echo $asd
    23
    
    ##静默输入
    [root@localhost ~]# read -s pass  ##输入后不会显示在屏幕上
    [root@localhost ~]# echo $pass
    1234
    
    ##添加提示信息
    [root@localhost ~]# read -p "input:"
    input:123
    
    ##利用界定符代替回车结束输入
    [root@localhost ~]# read -d ":" zxc   ##指定界定符为:
    123:[root@localhost ~]# echo $zxc
    123
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    字段分隔符与迭代器

    [root@localhost ~]# cat test.sh 
    # !/bin/bash
    #用途:演示IFS的用法
    line="root:x :0:0:root:/root:/bin/bash"
    oldIFS=$IFS;
    IFS=":"
    count=0
    for item in $line;
    do
    [ $count -eq 0 ] && user=$item;
    [ $count -eq 6 ] && shell=$item;
    let count++
    done;
    IFS=$o1dIFS
    echo $user \'s she1l is $shell;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    for循环

    [root@localhost ~]# for i in {a..z};do echo $i;done
    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
    
    [root@localhost ~]# for ((i=0;i<10;i++)) { echo $i; }
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    ##生成连续ip地址
    [root@localhost ~]# for i in 192.168.15.{1..10};do echo $i;done
    192.168.15.1
    192.168.15.2
    192.168.15.3
    192.168.15.4
    192.168.15.5
    192.168.15.6
    192.168.15.7
    192.168.15.8
    192.168.15.9
    192.168.15.10
    
    ##起始为1,步进为2,到10 结束
    [root@localhost ~]# for i in $(seq 1 2 10);do echo $i;done
    1
    3
    5
    7
    9
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    条件测试,循环等补充知识点

    命令使用

    cat 查看

    [root@localhost ~]# cat passwd 
    root:x:0:0:root:/root:/bin/bash
    
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    
    halt:x:7:0:halt:/sbin:/sbin/halt
    
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    
    
    
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# cat -n passwd    ##显示行号包括所有空白行
         1  root:x:0:0:root:/root:/bin/bash
         2  
         3  shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
         4  
         5  halt:x:7:0:halt:/sbin:/sbin/halt
         6  
         7  mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
         8  
         9  
        10  
        11  operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# cat -s passwd  ##压缩连续的空白行
    root:x:0:0:root:/root:/bin/bash
    
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    
    halt:x:7:0:halt:/sbin:/sbin/halt
    
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@localhost ~]# cat  passwd | tr -s '\n'  ## tr -s 删除重复出现的字符序列
    root:x:0:0:root:/root:/bin/bash
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    script,scriptreplay - 录制与查看终端会话

    script命令可以用作交互终端会话过程的记录,保留用户输入和系统输出的全过程。以备之后查询与学习。

    在下述语法中,输出文件是用于存储所有的上机会话过程。如果未指定输出文件,所有的会话过程将会写到当前工作目录的默认文件typescript中。

    语法格式:script [参数] [文件]
    
    常用参数:
    -a	把会话记录附加到typescript文件或指定的文件后面,保留先前的内容
    -c	运行指定的命令而非交互shell
    -r  子进程中返回退出代码
    -f  如果需要在输出到日志文件的同时,也可以查看日志文件的内容
    -q  可以使script命令以静默模式运行
    -t  指明输出录制的时间数据
    -V  输出script的版本信息,然后退出
    -h  输出script的help信息,然后退出
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    [root@localhost ~]# which script
    /usr/bin/script
    [root@localhost ~]# which scriptreplay
    /usr/bin/scriptreplay
    
    [root@localhost ~]# script -V
    script,来自 util-linux 2.23.2
    [root@localhost ~]# script 
    Script started, file is typescript
    [root@localhost ~]# exit
    exit
    Script done, file is typescript
    [root@localhost ~]# ll
    总用量 8
    -rw-r--r--. 1 root root 208 114 22:31 passwd
    -rw-r--r--. 1 root root 181 117 18:01 typescript
    
    ##静默模式
    [root@localhost ~]# script -q
    [root@localhost ~]# exit
    exit
    //没有任何提示
    
    
    [root@localhost ~]# script -c "ls -l"
    Script started, file is typescript
    总用量 4
    -rw-r--r--. 1 root root 208 114 22:31 passwd
    -rw-r--r--. 1 root root   0 117 22:40 typescript
    Script done, file is typescript
    
    [root@localhost ~]# ls
    passwd  typescript
    [root@localhost ~]# cat typescript 
    脚本启动于 20240117日 星期三 224013秒
    总用量 4
    -rw-r--r--. 1 root root 208 114 22:31 passwd
    -rw-r--r--. 1 root root   0 117 22:40 typescript
    
    Script done on 20240117日 星期三 224013//没加-a之前的内容全被清空了 相当于重定向
    
    [root@localhost ~]# script -t 2> time.log -a typescript  ## -t将时序导入stderr,2> 将stderr导入time.log
    Script started, file is typescript
    [root@localhost ~]# ls
    passwd  time.log  typescript
    [root@localhost ~]# touch 123
    [root@localhost ~]# ls
    123  passwd  time.log  typescript
    [root@localhost ~]# exit
    exit
    Script done, file is typescript
    [root@localhost ~]# ls
    123  passwd  time.log  typescript
    [root@localhost ~]# cat time.log   //时间序列数据
    0.605960 49
    0.031052 1
    2.154059 1
    0.127346 2
    0.248924 30
    0.002781 41
    0.000425 1
    1.548721 1
    0.151315 1
    0.223722 1
    0.209794 1
    0.142308 1
    0.288548 1
    1.160007 1
    0.359510 4
    0.672967 1
    0.247383 4
    0.632045 1
    0.112081 1
    0.216661 2
    0.497288 41
    0.002472 1
    1.507865 1
    0.183600 2
    0.448379 35
    0.002940 41
    0.000538 1
    2.332258 1
    0.247890 1
    0.151661 1
    0.169472 8
    [root@localhost ~]# cat typescript 
    脚本启动于 20240117日 星期三 224013秒
    总用量 4
    -rw-r--r--. 1 root root 208 114 22:31 passwd
    -rw-r--r--. 1 root root   0 117 22:40 typescript
    
    Script done on 20240117日 星期三 224013秒
    脚本启动于 20240117日 星期三 224336[root@localhost ~]# ls
    passwd  time.log  typescript
    [root@localhost ~]# touch 123
    [root@localhost ~]# ls
    123  passwd  time.log  typescript
    [root@localhost ~]# exit
    exit
    
    Script done on 20240117日 星期三 224351// 未设置时间同步
    
    
    [root@localhost ~]# scriptreplay time.log typescript   //按时间序列数据回放
    总用量 4
    -rw-r--r--. 1 root root 208 114 22:31 passwd
    -rw-r--r--. 1 root root   0 117 22:40 typescript
    
    Script done on 20240117日 星期三 224013秒
    脚本启动于 20240117日 星期三 224336
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114

    find 文件查找

    find命令的功能是根据给定的路径和条件查找相关文件或目录,可以使用的参数很多,并且支持正则表达式,结合管道符后能够实现更加复杂的功能,是系统管理员和普通用户日常工作必须掌握的命令之一。

    语法格式:find [路径] [参数]
    
    常用参数:
    -name	匹配名称
    -iname 匹配名称且忽略大小写
    -perm	匹配权限(mode为完全匹配,-mode为包含即可)
    -user	匹配所有者
    -group	匹配所有组
    -mtime -n +n	匹配修改内容的时间(-n指n天以内,+n指n天以前)
    -atime -n +n	匹配访问文件的时间(-n指n天以内,+n指n天以前)
    -ctime -n +n	匹配修改文件权限的时间(-n指n天以内,+n指n天以前)
    -nouser	匹配无所有者的文件
    -nogroup	匹配无所有组的文件
    -newer f1 !f2	匹配比文件f1新但比f2旧的文件
    -type b/d/c/p/l/f	匹配文件类型(后面的字幕字母依次表示块设备、目录、字符设备、管道、链接文件、文本文件)
    -size	匹配文件的大小(+50KB为查找超过50KB的文件,而-50KB为查找小于50KB的文件)
    -prune	忽略某个目录
    -exec …… {}\;	后面可跟用于进一步处理搜索结果的命令
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    [root@localhost ~]# find . -print  ##打印当前目录下所有文件
    .
    ./.bash_logout
    ./.bash_profile
    ./.bashrc
    ./.cshrc
    ./.tcshrc
    ./.bash_history
    ./passwd
    ./.viminfo
    ./typescript
    ./time.log
    ./123
    //-print是默认的不加也可以
    
    ##反向匹配所有不以log结尾的
    [root@localhost ~]# find .  ! -name "*.log"
    .
    ./.bash_logout
    ./.bash_profile
    ./.bashrc
    ./.cshrc
    ./.tcshrc
    ./.bash_history
    ./passwd
    ./.viminfo
    ./typescript
    ./123
    
    ##路径匹配
    [root@localhost ~]# find / -path "*sysconfig*"
    find: ‘/proc/15773’: 没有那个文件或目录
    /run/initramfs/state/etc/sysconfig
    /run/initramfs/state/etc/sysconfig/network-scripts
    /etc/sysconfig
    /etc/sysconfig/ip6tables-config
    /etc/sysconfig/iptables-config
    。。。
    
    ## 基于目录深度的搜索
    [root@localhost ~]# find / -maxdepth 1 -type f 
    /nohup_xxl-job-admin.log
    [root@localhost ~]# find / -maxdepth 2 -type f 
    /boot/.vmlinuz-3.10.0-693.el7.x86_64.hmac
    /boot/System.map-3.10.0-693.el7.x86_64
    /boot/config-3.10.0-693.el7.x86_64
    /boot/symvers-3.10.0-693.el7.x86_64.gz
    /boot/vmlinuz-3.10.0-693.el7.x86_64
    。。。
    
    ##-newer 找出比对比文件更长的文件
    [root@localhost ~]# find . -type f -newer time.log 
    ./.bash_history
    ./passwd
    ./.viminfo
    ./typescript
    ./123
    
    
    ##-delete 删除找出的文件
    [root@localhost ~]# find . -type f   -newer time.log -delete
    [root@localhost ~]# ls
    time.log
    
    ##-exec 表示将找到的文件交给下一步{} 代表找到的文件
    [root@localhost ~]# find . -type f  -name "*.log" -exec mv {} 123 \;
    [root@localhost ~]# ls
    123
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    xargs 格式化从标准输出的数据,传递给下一个参数

    xargs命令默认接收的信息中,空格是默认定界符,所以可以接收包含换行和空白的内容。

    [root@localhost ~]# find . -type f -name "*.txt" -print | xargs echo
    ./abc.txt ./123.txt
    
    [root@localhost ~]# find . -type f -name "*.txt" -print | xargs  rm -f
    [root@localhost ~]# ls
    123
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    tr 转换

    r命令是一款批量字符转换、压缩、删除的文本工具,但仅能从标准输入中读取文本内容,需要与管道符或输入重定向操作符搭配使用。

    语法格式:tr [参数] 字符串1 字符串2
    
    常用参数:
    -c	反选字符串1的补集(取反)
    -d	删除字符串1中出现的所有字符
    -s	删除所有重复出现的字符序列
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    ##大小写转换
    [root@localhost ~]# echo "HELLO WORLD" | tr 'A-Z' 'a-z'
    hello world
    [root@localhost ~]# echo "HELLO WORLD" | tr L l
    HEllO WORlD
    [root@localhost ~]# echo "HELLO WORLD" | tr H h
    hELLO WORLD
    
    ##通过数字映射加密
    [root@localhost ~]# echo 12345 | tr '0-9' '9876543210'
    87654               ##已加密 通过映射将原来的12345转换为87654
    
    ##反过来替换解密
    [root@localhost ~]# echo 87654  | tr '9876543210' '0-9'
    12345
    
    ##删除不想要的数据
    [root@localhost ~]# echo "Hello 123 world 456" |  tr -d '0-9'
    Hello  world       ##将stdin中的数字删除并打印出来
    
    ##字符串补集
    [root@localhost ~]# echo hello 1 char 2 next 3 | tr -d -c '0-9 \n'
     1  2  3
    [root@localhost ~]# echo hello 1 char 2 next 3 | tr -d -c '0-9'
    123
    
    ##压缩连续的重复字符
    [root@localhost ~]# echo hello      char    next  | tr -s ' '
    hello char next
    //压缩的重复的连续空格
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    简单实践

    //计算下列数字和
    [root@localhost ~]# cat sum.txt 
    1
    2
    3
    4
    5
    7
    9
    [root@localhost ~]# cat sum.txt | echo $[ $(tr '\n' '+') 0 ]
    31
    //将每行的换行符替换为+号,但是最后一行9+ 没有操作数所有需要在外面加个0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • tr可以像使用集合一样使用各种不同的字符类,这些字符类如下所示。
    xdigit十六进制字符
    alnum字母和数字
    alpha字母
    cntrl控制(非打印)字符
    digit数字
    grap图形字符
    lower小写字母
    print可打印字符
    punct标点符号
    space空白字符
    upper大写字母
    [root@localhost ~]# echo hello 1 char 2 next 3 | tr '[:lower:]' '[:upper:]'
    HELLO 1 CHAR 2 NEXT 3
    //小写转大写
    
    • 1
    • 2
    • 3

    sort,uniq 排序单一,与重复

    语法格式:sort [参数] 文件
    
    常用参数:
    -b	忽略每行前面开始出的空格字符
    -c	检查文件是否已经按照顺序排序
    -d	除字母、数字及空格字符外,忽略其他字符
    -f	将小写字母视为大写字母
    -i	除040至176之间的ASCII字符外,忽略其他字符
    -m	将几个排序号的文件进行合并
    -M	将前面3个字母依照月份的缩写进行排序
    -n	依照数值的大小排序
    -o <输出文件>	将排序后的结果存入制定的文件
    -r	以相反的顺序来排序
    -t <分隔字符>	指定排序时所用的栏位分隔字符
    -k	指定需要排序的栏位
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    ##按字母排序
    [root@localhost ~]# cat apple.txt 
    banana
    pear
    apple
    orange
    raspaberry
    [root@localhost ~]# sort apple.txt 
    apple
    banana
    orange
    pear
    raspaberry
    
    ##按开头数字排序
    [root@localhost ~]# cat number.txt 
    45
    12
    3
    98
    82
    67
    24
    56
    9
    2324
    2
    4
    a
    c
    bc
    a
    [root@localhost ~]# sort number.txt 
    12
    2
    2324
    24
    3
    4
    45
    56
    67
    82
    9
    98
    a
    a
    bc
    c
    
    ##按数字大小排序
    [root@localhost ~]# sort -n number.txt 
    a
    a
    bc
    c
    2
    3
    4
    9
    12
    24
    45
    56
    67
    82
    98
    2324
    
    
    ##通过列进行排序
    [root@localhost ~]# cat data.txt 
    1   centos  790
    2   linux   300
    3   euleros 500
    4   ubantu  1000
    5  oracle   501
    6   unix     10000
    [root@localhost ~]# sort -nk 1 data.txt //n以大小排序 k指定列 
    1   centos  790
    2   linux   300
    3   euleros 500
    4   ubantu  1000
    5  oracle   501
    6   unix     10000
    
    [root@localhost ~]# sort -nk 3 data.txt 
    2   linux   300
    3   euleros 500
    5  oracle   501
    1   centos  790
    4   ubantu  1000
    6   unix     10000
    [root@localhost ~]# sort -nkr 3 data.txt  //k指定行号 放最后面
    sort: 区块起始处的编号无效:在"r" 处的计数无效
    [root@localhost ~]# sort -nrk 3 data.txt 
    6   unix     10000
    4   ubantu  1000
    1   centos  790
    5  oracle   501
    3   euleros 500
    2   linux   300
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102

    uniq 消除重复行

    语法格式:uniq [参数] 文件
    
    常用参数:
    -c	打印每行在文本中重复出现的次数
    -d	每个重复纪录只出现一次
    -u	只显示没有重复的纪录
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    [root@localhost ~]# cat cont.txt 
    hack
    hack
    apple
    oppo
    xiaomi
    apple
    
    [root@localhost ~]# uniq cont.txt  ##消除相邻重复行
    hack
    apple
    oppo
    xiaomi
    apple
    
    [root@localhost ~]# uniq -c  cont.txt ##消除重复行并统计重复次数,空行也算
          2 hack
          1 apple
          1 oppo
          1 xiaomi
          1 apple
          1 
    
    [root@localhost ~]# sort cont.txt | uniq -d  ##打印文件重复行
    apple
    hack
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    校验和与核实

    校验和(checksum)程序用来从文件中生成校验和密钥,然后利用这个校验和密钥核实文件完整性。一份文件可以通过网络或任何存储介质分发到不同的地点。出于多种原因,数据有可能丢失或损坏。这时就需要利用校验和来验证文件完整性,特别是数据库备份脚本。

    -md5sum 一个32字符的16进制串

    [root@localhost ~]# md5sum sum.txt 
    d6fcd506544a5b3a46f7f9d21dced3cf  sum.txt
    [root@localhost ~]# md5sum sum.txt > sum.md5
    [root@localhost ~]# md5sum -c sum.md5 
    sum.txt: 确定
    
    • 1
    • 2
    • 3
    • 4
    • 5

    -sha1sum 一个40字符的16进制串

    [root@localhost ~]# sha1sum sum.txt 
    b5a29a0473702a7a3a2068aa55bc5a8fe7bb0592  sum.txt
    [root@localhost ~]# sha1sum sum.txt > sum.sha1
    [root@localhost ~]# sha1sum -c sum.sha1
    sum.txt: 确定
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    临时文件命名与随机随机数

    编写shell脚本时,我们经常需要存储临时数据。最适合存储临时数据的位置是/tmp(该目录中的内容在系统重启后会被清空)。有两种方法可以为临时数据生成标准的文件名。

    • 利用随机数
    [root@localhost ~]# echo $RANDOM  ##返回一个随机数
    991
    
    temp_file=" / tmp /file-$RANDOM"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 利用进程id
    temp_file=" /tmp/var.s$"  ##.$$ 作为添加的后缀会被扩展成当前运行脚本的进程ID。
    
    
    [root@localhost ~]# cat test.sh 
    #!/bin/sh
    
    temp_file=/tmp/var.$$
    echo $temp_file
    
    [root@localhost ~]# chmod +x test.sh 
    [root@localhost ~]# ./test.sh 
    /tmp/var.12280
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    分割文件与日志

    dd 拷贝与转换文件

    dd命令来自于英文词组“disk dump”的缩写,其功能是用于拷贝及转换文件。使用dd命令可以按照指定大小的数据块来拷贝文件,并在拷贝的过程中对内容进行转换。
    
    语法格式:dd 参数 对象
    
    常用参数:
    -v	显示版本信息
    -h	显示帮助信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    [root@localhost ~]# dd if=/dev/zero bs=100k count=1 of=data.file
    记录了1+0 的读入
    记录了1+0 的写出
    102400字节(102 kB)已复制,0.000726083 秒,141 MB/秒
    [root@localhost ~]# ls
    data.file  
    [root@localhost ~]# du -sh *   ##查看文件大小
    100K    data.file
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    split 切割文件

    split命令可以将大文件分割成较小的文件,在默认情况下将按照每1000行切割成一个小文件 。
    
    语法格式:split [参数] [切割文件][文件名]
    
    常用参数:
    -b	指定每多少字节切成一个小文件
    --help 	查看帮助信息
    --version 	显示版本信息
    -C	与参数”-b”相似,但是在切割时将尽量维持每行的完整性 
    -d   后缀使用数字
    -a   指定后缀长度
    -l   指定行数分割
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    [root@localhost ~]# split -b 10k data.file  ##以10k切割
    [root@localhost ~]# ls
    data.file  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj
    
    [root@localhost ~]# split -b 10k data.file -d -a 3 ##-d以数字切割 -a 指定后缀长度
    [root@localhost ~]# ls
    data.file  x000  x001  x002  x003  x004  x005  x006  x007  x008  x009  xaa  xab  xac  xad  xae  xaf  xag  xah  xai  xaj
    //除了k,还可以使用M (MB)、c (GB)、c (byte)、w (word)
    
    [root@localhost ~]# split -b 10k data.file -d -a 3 split_file ## 修改前缀名字
    [root@localhost ~]# ls
    data.file  split_file000  split_file001  split_file002  split_file003  split_file004  split_file005  split_file006  split_file007  split_file008  split_file009
    
    [root@localhost ~]# split -8 /etc/passwd   ##按行切割
    [root@localhost ~]# ls
    data.file  xaa  xab  xac
    [root@localhost ~]# cat xa
    xaa  xab  xac  
    [root@localhost ~]# cat xaa
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    
    [root@localhost ~]# rm -f x*
    [root@localhost ~]# split -l 8 /etc/passwd    ##l可省略
    [root@localhost ~]# ls
    data.file  xaa  xab  xac
    [root@localhost ~]# cat xaa
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    csplit 根据文本特点分割文件

    语法参数:csplit [参数]
    
    常用参数:
    -b<输出格式>或--suffix-format=<输出格式> 	预设的输出格式其文件名称为xx00,xx01等,用户可以通过改变<输出格式>来改变输出的文件名
    -f<输出字首字符串>或--prefix=<输出字首字符串> 	预设的输出字首字符串其文件名为xx00,xx01等,如果制定输出字首字符串为“hello”,则输出的文件名称会变成hello00,hello、01……
    -k或--keep-files 	保留文件,就算发生错误或中断执行,与不能删除已经输出保存的文件
    -n<输出文件名位数>或--digits=<输出文件名位数> 	预设的输出文件名位数其文件名称为xx00,xx01……如果用户指定输出文件名位数为“3”,则输出的文件名称会变成xx000,xx001等
    -q或-s或--quiet或--silent 	不显示指令执行过程
    -z或--elide-empty-files 	删除长度为0 Byte文件。 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    [root@localhost ~]# cat server.log 
    SERVER一1
    [connection] 192.168.0.1 success
    [connection] 192.168.0.2 failed
    [diaconnect] 192.168.0.3 pending
    [connection] 192.168.0.4 success
    SERVER-2
    [connection] 192.168.0.1 failed
    [connection] 192.168.0.2 fai1ed
    [disconnect] 192.168.0.3 success
    [connection] 192.168.0.4 failed
    
    [root@localhost ~]# csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log" ; rm -f server00.log
    [root@localhost ~]# ls
    data.file  server01.log  server02.log  server.log
    [root@localhost ~]# cat server01.log 
    SERVER一1
    [connection] 192.168.0.1 success
    [connection] 192.168.0.2 failed
    [diaconnect] 192.168.0.3 pending
    [connection] 192.168.0.4 success
    [root@localhost ~]# cat server02.log 
    SERVER-2
    [connection] 192.168.0.1 failed
    [connection] 192.168.0.2 fai1ed
    [disconnect] 192.168.0.3 success
    [connection] 192.168.0.4 failed
    
    /SERVER/用来匹配某一行,分割过程即从此处开始。
    /[REGEX]/表示文本样式。包括从当前行(第一行)直到(但不包括)包含“SERVER"的匹配行。
    {*}表示根据匹配重复执行分割,直到文件末尾为止。可以用{整数}的形式来指定分割执行的次数。
    -s使命令进入静默模式,不打印其他信息。
    -n指定分割后的文件名后缀的数字个数,例如01、02、03等。
    -f指定分割后的文件名前缀(在上面的例子中,server就是前缀)-b指定后缀格式。例如“%02d.log”,类似于C语言中printf的参数格式。在这里文件名=前缀+后缀=server + %02d.log。
    因为分割后的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我们删掉分割的第一行也就是server00.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    根据扩展名提取文件名

    有一些脚本是依据文件名进行各种处理的。我们可能会需要在保留扩展名的同时修改文件名、转换文件格式(保留文件名的同时修改扩展名)或提取部分文件名。shell具有的内建功能可以依据不同的情况来切分文件名。

    ##提取名称
    [root@localhost ~]# file_jpg="sample.jpg"
    [root@localhost ~]# name=${file_jpg%.*}
    [root@localhost ~]# echo file name is $name
    file name is sample
    
    
    ${VAR%.*〕的含义是:
    从$VARIABLE中删除位于%右侧的通配符(在前例中是.*)所匹配的字符串。通配符从右向左进行匹配。
    给VAR赋值,VAR=sample.jpg。那么,通配符从右向左就会匹配到.jpg,因此,从$VAR中删除匹配结果,就会得到输出“sarnple”。
    
    %属于非贪婪操作,他找出从右到左匹配通配符的最短结果
    %%属于贪婪操作, 他会找出符合条件的最长字符串
    例如:
    [root@localhost ~]# var=123.abc.256.789.txt
    [root@localhost ~]# echo ${var%%.*}
    123
    [root@localhost ~]# echo ${var%.*}
    123.abc.256.789
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    ##提取扩展名
    [root@localhost ~]# extension=${file_jpg#*.}
    [root@localhost ~]# echo $extension
    jpg
    
    #与%类似只是顺序相反。
    #是从左往右进行匹配
    
    [root@localhost ~]# var=123.abc.256.789.txt
    [root@localhost ~]# echo ${var#*.}
    abc.256.789.txt
    [root@localhost ~]# echo ${var##*.}
    txt
    //当文件有多个扩展名的时候,使用##贪婪匹配能更准确的提取出扩展名
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    批量重命名与移动

    [root@localhost ~]# cat rename.sh 
    #!/bin/bash
    #文件名rename.sh
    count=1;
    for img in *.log
    do
    new=image-$count.${img##*.}
    
    mv "$img" "$new" 2> /dev/null
    
    if [ $? -eq 0 ];then
    
    echo "Renaming $img to $new"
    let count++
    
    fi
    done
    
    [root@localhost ~]# ls
    data.file  rename.sh  server01.log  server02.log  server.log
    
    [root@localhost ~]# ./rename.sh 
    Renaming server01.log to image-1.log
    Renaming server02.log to image-2.log
    Renaming server.log to image-3.log
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    交互输入自动化

    ##简单交互
    [root@localhost ~]# cat test.sh 
    #!/bin/bash
    
    read -p "你想打印什么?" print1
    
    echo $print1
    [root@localhost ~]# chmod +x test.sh 
    [root@localhost ~]# ./test.sh 
    你想打印什么?123
    123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    read 从标准输入中读取数值

    read命令的功能是用于读取单行数据内容,一般是从标准输入中读取数值,用于给变量赋值。

    语法格式:read [参数]
    
    常用参数:
    -a 	定义一个数组,以空格为间隔符进行赋值
    -d 	定义一个结束标志
    -p	设置提示信息
    -e	在输入的时候可以使用命令补全功能
    -n	定义输入文本的长度
    -r	禁用转义符(\)
    -s	输入字符不在屏幕显示
    -t	限定最长等待时间
    -u	从文件描述符中读入信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    ##简单交互自动化 \n等于回车
    [root@localhost ~]# echo -e  "123\n" | ./test.sh 
    123
    
    
    ##简单升级一下
    [root@localhost ~]# cat test.sh 
    #!/bin/bash
    
    read -p "你想打印什么?" print1
    read -p "你还想打印什么?" print2
    echo $print1
    echo $print2
    [root@localhost ~]# ./test.sh 
    你想打印什么?234
    你还想打印什么?567
    234
    567
    
    
    [root@localhost ~]# echo -e  "123\nabc\n" | ./test.sh 
    123
    abc
    
    ##输入较多时可以制作输入文件
    [root@localhost ~]# echo -e  "cvb\n789\n"  > input.txt
    [root@localhost ~]# cat input.txt 
    cvb
    789
    
    [root@localhost ~]# ./test.sh < input.txt 
    cvb
    789
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    除此之外还可以使用一些函数例如expect

    文件管理

    UNIX将操作系统中的一切都视为文件。文件与每一个操作息息相关,而我们可以利用它们进行各种与系统或进程相关的处理工作。例如,我们所使用的命令终端就是和一个设备文件关联在一起的。

    有各种不同形式的文件,比如目录、普通文件、块设备、字符设备、符号链接、套接字和命名管道等。

    文件的属性包括文件名、大小、文件类型、文件内容修改时间(modification time)、文件访问时间(access time)、文件属性更改时间(change time)、i节点、链接以及文件所在的文件系统

    生成任意大小的文件

    创建特定文件最简单的办法就是使用dd命令,此法在上文分割文件也提到过,在此详细介绍一下。

    ##if代表输入文件,of代表输出文件,bs指定大小,count指定块
    [root@localhost ~]# dd if=/dev/zero of=junk.data bs=1M count=1
    记录了1+0 的读入
    记录了1+0 的写出
    1048576字节(1.0 MB)已复制,0.00126048 秒,832 MB/秒
    [root@localhost ~]# du -sh junk.data 
    1.0M    junk.data
    /// /dev/zero是一个字符设备,它会不断返回0值字节。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果不指定输入参数(if),默认情况下dd会从stdin中读取输入。与之类似,如果不指定输出参数(of),则dd会将stdout作为默认输出。

    文本文件的交集与差集

    comm 比较差异

    comm命令可用于两个文件之间的比较。它有很多不错的选项可用来调整输出,以便我们执行交集、求差(difference)以及差集操作。

    • 交集:打印出两个文件所共有的行。
    • 求差:打印出指定文件所包含的且不相同的那些行。
    • 差集:打印出包含在文件A中,但不包含在其他指定文件中的那些行。
    [root@localhost ~]# cat A.txt 
    apple
    orange
    gold
    silver
    steel
    [root@localhost ~]# cat B.txt 
    orange
    gold
    cookies
    carrot
    [root@localhost ~]# comm A.txt B.txt  //comm必须使用排过序的文件作为输入
    apple
                    orange
    comm: 文件1 没有被正确排序
    comm: 文件2 没有被正确排序
                    gold
            cookies
            carrot
    silver
    steel
    [root@localhost ~]# sort A.txt -o A.txt ;sort B.txt -o B.txt 
    //-o 将排过序结果输入指定文件
    [root@localhost ~]# comm A.txt B.txt 
    apple
            carrot
            cookies
                    gold
                    orange
    silver
    steel
    ##输出的第一列包含只在A.txt中出现的行,第二列包含只在B.txt中出现的行,第三列包含A.txt和B.txt中相同的行。各列以制表符(t)作为定界符。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    有一些选项可以按照我们的需求进行格式化输出,
    例如:
    -1 从输出中删除第一列
    -2 从输出中删除第二列
    -3 从输出中删除第三列

    //删除第一,二列,便只会打印出他们的交集
    [root@localhost ~]# comm A.txt B.txt -1 -2
    gold
    orange
    
    //取出全集,并删除制表符转化为单列
    [root@localhost ~]# comm A.txt B.txt -3 | sed 's/^\t//'
    apple
    carrot
    cookies
    silver
    steel
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    查找并删除重复文件

    此处的重复文件指内容一样的文件,而不是名字相同的文件。
    在前面校验和里面提到过,相同的文件内容的校验和也是相同的。

    ##创建测试文件及副本
    [root@localhost ~]# echo "hello"  > test ; cp test test_copy1 ; cp test test_copy2;
    [root@localhost ~]# echo "next" > other
    
    [root@localhost ~]# vim remove.sh
    #!/ bin/ bash
    #文件名:remove_duplicates.sh
    #用途:查找并删除重复文件,每一个文件只保留一个样本
    ls -lS | awk "BEGIN {
    getline;getline;
    name1=$8 ; size=$5
    }
    {name2=$8 ;
    if (size==$5)
    {
    "md5sum "name1 | getline; csum1=$1;
    "md5sum "name2 | getline; csum2=$1;
    if ( csum1==csum2 )
    {print name1 ; print name2 }};
    size=$5; name1=name2 ;
    }'| sort -u > duplicate_files
    cat duplicate_files | xargs -I { } md5sum { } | sort | uniq -w 32 | awk '{ print "^"$2"$" }'| sort -u > duplicate_sample
    echo Removing . .
    comm duplicate.files duplicate_sample -2 -3 | tee /dev/stderr | xargs rm
    echo Removed duplicates files successfully.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    创建不可删除文件

    [root@localhost ~]# cat /etc/mtab 
    rootfs / rootfs rw 0 0
    sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0
    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
    devtmpfs /dev devtmpfs rw,seclabel,nosuid,size=6058616k,nr_inodes=1514654,mode=755 0 0
    securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0
    tmpfs /dev/shm tmpfs rw,seclabel,nosuid,nodev 0 0
    .....
    #可以查看分区设备路径与文件系统类型
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    chattr 修改文件属性

    不可修改属性是保护文件不被修改的安全手段之一。最有代表性的例子就是/etc/shadow文件。该文件由当前系统中所有用户的加密密码组成。我们通过密码才能够登录系统。用户通常用passwd命令修改自己的密码。执行passwd时,它实际上就修改了letc/shadow文件。我们可以将shadow文件设置为不可修改,这样就再没有用户能够修改密码了。

    [root@localhost ~]# useradd test
    [root@localhost ~]# passwd test
    更改用户 test 的密码 。
    新的 密码:
    无效的密码: 密码少于 8 个字符  ##不影响修改
    重新输入新的 密码:
    passwd:所有的身份验证令牌已经成功更新。
    [root@localhost ~]# chattr +i /etc/shadow  ##添加不可修改属性
    [root@localhost ~]# passwd test
    更改用户 test 的密码 。
    新的 密码:
    无效的密码: 密码少于 8 个字符
    重新输入新的 密码:
    passwd: 鉴定令牌操作错误 
    [root@localhost ~]# echo '12345' | passwd --stdin test
    更改用户 test 的密码 。
    passwd: 鉴定令牌操作错误
    [root@localhost ~]# chattr -i /etc/shadow   ##移除不可修改属性
    [root@localhost ~]# echo '12345' | passwd --stdin test
    更改用户 test 的密码 。
    passwd:所有的身份验证令牌已经成功更新。
    //移除不可修改属性后,可以正常修改
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    批量生成空白文件

    touch 创建文件

    touch命令的功能是用于创建空文件与修改时间戳。如果文件不存在,则会创建出一个空内容的文本文件;如果文件已经存在,则会对文件的Atime(访问时间)和Ctime(修改时间)进行修改操作,管理员可以完成此项工作,而普通用户只能管理主机的文件。

    语法格式:touch [参数] 文件
    
    常用参数:
    -a	改变档案的读取时间记录
    -m 	改变档案的修改时间记录
    -r	使用参考档的时间记录,与 --file 的效果一样
    -c	不创建新文件
    -d	设定时间与日期,可以使用各种不同的格式
    -t	设定档案的时间记录,格式与 date 命令相同
    --no-create 	不创建新文件
    --help	显示帮助信息
    --version	列出版本讯息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    #1
    [root@localhost test1]# touch {1..100}.py
    [root@localhost test1]# ls
    100.py  13.py  17.py  20.py  24.py  28.py  31.py  35.py  39.py  42.py  46.py  4.py   53.py  57.py  60.py  64.py  68.py  71.py  75.py  79.py  82.py  86.py  8.py   93.py  97.py
    10.py   14.py  18.py  21.py  25.py  29.py  32.py  36.py  3.py   43.py  47.py  50.py  54.py  58.py  61.py  65.py  69.py  72.py  76.py  7.py   83.py  87.py  90.py  94.py  98.py
    11.py   15.py  19.py  22.py  26.py  2.py   33.py  37.py  40.py  44.py  48.py  51.py  55.py  59.py  62.py  66.py  6.py   73.py  77.py  80.py  84.py  88.py  91.py  95.py  99.py
    12.py   16.py  1.py   23.py  27.py  30.py  34.py  38.py  41.py  45.py  49.py  52.py  56.py  5.py   63.py  67.py  70.py  74.py  78.py  81.py  85.py  89.py  92.py  96.py  9.py
    #2
    [root@localhost test1]# for i in {1..10}.php; do touch $i; done 
    [root@localhost test1]# ls
    10.php  1.php  2.php  3.php  4.php  5.php  6.php  7.php  8.php  9.php
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    列举文件类型统计信息

    file 识别文件类型

    ile命令的功能是用于识别文件的类型,也可以用来辨别一些内容的编码格式。由于Linux系统并不是像Windows系统那样通过扩展名来定义文件类型,因此用户无法直接通过文件名来进行分辨。file命令则是为了解决此问题,通过分析文件头部信息中的标识来显示文件类型,使用很方便。

    语法格式:file [参数] 文件
    
    常用参数:
    -b	列出辨识结果时,不显示文件名称 (简要模式)
    -c	详细显示指令执行过程
    -f	指定名称文件,显示多个文件类型信息
    -L	直接显示符号连接所指向的文件类别
    -m	指定魔法数字文件
    -v	显示版本信息
    -z	尝试去解读压缩文件的内容
    -i	显示MIME类别
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    [root@localhost ~]# file test
    test: ASCII text
    [root@localhost ~]# file -i test
    test: text/plain; charset=us-ascii
    
    
    
    [root@localhost ~]# cat filestat.sh 
    #!/bin/bash
    #文件名: filestat.sh
    if [ $# -ne 1 ];then  
      echo $0 basepath;
      echo
    fi
    path=$1
    
    declare -A statarray;
    while read line;
    do
      ftype=`file -b "$line"`
      let statarray["$ftype"]++;
    done< <( find $path -type f -print)
    
    for ftype in "${!statarray[@]}";
    do
      echo $ftype : ${statarray["$ftype"]}
    done
    
    [root@localhost ~]# ./filestat.sh test
    ASCII text : 1
    [root@localhost ~]# ./filestat.sh test1
    empty : 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在脚本中声明了一个关联数组statarray,这样可以用文件类型作为数组索引,将每种文件类型的数量存入数组。每次遇到一个文件类型,就用1et增加计数。find命令以递归的方式获取文件路径列表。脚本中的ftype='file -b "$line"使用file命令获得文件类型信息。

    <(find $path -type f -print)等同于文件名。只不过它用子进程输出来代替文件名。注意这里还有另外一个<。
    ${ !statarray [@]}用于返回一个数组索引列表。

  • 相关阅读:
    mysql 索引选取规则
    除了chatGPT网站外,国内有些可以使用的AI网站 文心一言 讯飞星火 豆包 通义千问 人工智能网站 AI网站
    微信小程序毕业设计-英语互助系统项目开发实战(附源码+论文)
    5G业务正式商用,属于广电的机会在哪?
    java面向对象(三)
    Springboot-mybatis创建项目报错day01
    ​如何使用ArcGIS Pro制作一张地形图
    阿里发布大模型发布图结构长文本处理智能体,超越GPT-4-128k
    Code Llama: Open Foundation Models for Code
    Kafka topic分区增加副本
  • 原文地址:https://blog.csdn.net/weixin_46115601/article/details/124007708