day23:文档第五行增内容|每月1号压缩/etc/目录|过滤文本重复次数多的10个单词|人员分组|比较两个数大小...

1、在文本文档1.txt里第五行下面增加如下内容;两个方法;

# This is a test file.
# Test insert line into this file.

分析:给文档后增加内容,可以用sed 来搞定;也可以用while  do   done  循环;

sed 里面有一个 a 选项, 表示追加 5a 表示在第五行下面增加,直接写增加的内容, \n 表示换行;

1):收下定义一个 临时文件1.txt 内容:(包含 1  到 6 行);然后再使用 sed  命令;   -i  表示修改源文件;

sed  -i  '5a# This is a test file.\n# Test insert line into this file.'   1.txt

[root@localhost_002 shell100]# cat 1.txt
yuanhh
yuanhh
fenye
yuan
yuanhaohao
yhh
[root@localhost_002 shell100]# sed '5a# This is a test file.\n# Test insert line into this file.' 1.txt
yuanhh
yuanhh
fenye
yuan
yuanhaohao
# This is a test file.
# Test insert line into this file.
yhh

2):写一个计数器 0 ,使用while 循环分别读取每一行的内容,每读取一行就用计数器加 1,然后用if  判断,当循环到第五行的时候,然后打印一下要增加的内容(echo -e来增加一行内容);

脚本内容如下:while     read     line    do      done

[root@localhost_002 shell100]# cat 56.sh 
#!/bin/bash
#这个脚本用来给文件增加行内容;
#作者:yuanhh
n=0
cat 1.txt|while read line
do
    n=$[$n+1]
    if [ $n -eq 5 ]
    then
        echo $line
    echo -e "This is a test file.\n# Test insert line into this file."
    else
       echo $line
   fi
done
#执行脚本;
[root@localhost_002 shell100]# sh 56.sh
yuanhh
yuanhh
fenye
yuan
yuanhaohao
This is a test file.
# Test insert line into this file.
yhh

2、设计一个 shell 程序,在每月第一天自动备份并压缩 /etc/ 目录的所有内容,存放在 /root/bakup目录,文件名格式: yymmdd_etc/.tar.gz

注释:执行有两种方法

1: 可以自定义脚本内容,然后放到 crontab 里,每月 1 号来执行;

2: 可以自己在脚本里面判断是否 1 号,然后执行即可;如下就是这种方法;

注释 yy  表示年  mm 表示月    dd  表示日

1:年月日  yymmdd           可以用      date  +%y%m%d

[root@localhost_002 shell100]# date +%y%m%d
190118

2:每月第一天要怎么区别:            date  -d  '-17  day'    +%d        #因为今天18号,所有要减去 17 ,正好是 01 ,则每月1 号

[root@localhost_002 shell100]# date +%d
18
[root@localhost_002 shell100]# date -d '-17 day' +%d
01

注释:开头可用 if  来判断是否等于 01 ,如果则执行压缩命令;  不过也要判断下备份目标目录 /root/bakup 是否存在,不存在则创建;

注释:打包前,先 cd /etc/ 目录后再打包,这样打包的文件是/etc/目录里面的,不会包含 /etc/  目录本身;

在目录外压缩;   包含/etc/ 这个目录本身;
[root@localhost_002 /]# cd /
[root@localhost_002 /]# tar czf etc.tar.gz etc/   #目录外压缩/etc/ 目录;
[root@localhost_002 /]# du -sh etc.tar.gz         #大小不一样了;
19M	etc.tar.gz
[root@localhost_002 /]# tar tf etc.tar.gz |head -n10   
etc/                        #也包含了/etc/ 这个目录;
etc/fstab
etc/crypttab
etc/mtab
etc/resolv.conf
etc/grub.d/
etc/grub.d/00_header
etc/grub.d/01_users
etc/grub.d/10_linux
etc/grub.d/20_linux_xen

进入目录内压缩;  则不包含 /etc/这个目录本身;
[root@localhost_002 etc]# tar -czvf etc.tar.gz ./
[root@localhost_002 etc]# du -sh etc.tar.gz 
128M	etc.tar.gz                            #大小也不一样了;
[root@localhost_002 etc]# tar tf etc.tar.gz |head -n10  #发现不包含 /etc/ 目录本身;d
./
./fstab
./crypttab
./mtab
./resolv.conf
./grub.d/
./grub.d/00_header
./grub.d/01_users
./grub.d/10_linux
./grub.d/20_linux_xen

注释:打包前,先 cd /etc/ 目录后再打包,这样打包的文件是/etc/目录里面的,并不会包含 /etc/  目录本身;

脚本代码:首先定义三个变量:  d1  判断每月1号           d2  定义保存名称             dir   定义目录  然后判断月一号 及目录是否存在即可;

[root@localhost_002 shell100]# cat 57.sh 
#!bin/bash
#这个脚本用来每月1号压缩/etc/目录;
#作者:  yuanhh
d1=`date -d '-17 day' +%d`   #因为要运行脚本,这些需要推17天回去,然后到一号;
d=`date +%y%m%d`             #定义保存的年月日;
dir="/root/bakup"
if [ $d1 == "01" ]           #判断是否是 1 号;
then
    if [ ! -d $dir ]         #判断目录是否存在;
    then
        mkdir $dir
    fi
    cd /etc/
    tar zcf $dir/$d\_etc.tar.gz ./      #压缩目录,注意这个脱义字符哟;
fi

执行脚本;   
[root@localhost_002 shell100]# sh 57.sh 
[root@localhost_002 shell100]# ls -ld /root/bakup/190118_etc.tar.gz 
-rw-r--r-- 1 root root 212387814 1月  18 18:15 /root/bakup/190118_etc.tar.gz

注释:在上图例中,有 tar zcf $dir/$d\_etc.tar.gz ./  压缩目录命令,要得到后缀名为  190118_etc..tar.gz    \_要加脱义字符;不符合题意要求;

#不脱义每次压缩前面的日期和etc格式都不显示;
[root@localhost_002 etc]# echo $d
190118
[root@localhost_002 etc]# tar zcf /root/backup/$d_etc.tar.gz ./
[root@localhost_002 etc]# ls /root/backup/
.tar.gz 
#这样就可以了,原来是_这个需要脱义,前面要加\_才可以了;
[root@localhost_002 etc]# tar zcf /root/backup/$d\_etc.tar.gz ./
[root@localhost_002 etc]# ls /root/backup/
190118_etc.tar.gz 

3、把文件里面单词的重复次数计算出来,并且列出重复次数最多的10个单词;

那么如何来把所有单词找出来了; 用sed 可以轻易实现,当把所有非字母的字符替换为空格,剩下的就是单词了;|或者加入for 循环;

   cat 3.txt|sed 's#[^a-zA-Z]# #g'|xargs -n1|sort|uniq -c|sort -nr|head     

[root@localhost_002 shell100]# cat 3.txt|sed 's#[^a-zA-Z]# #g'|xargs -n1|sort|uniq -c|sort -nr|head
     21 x
     20 sbin
     14 nologin
      8 bin
      6 var
      5 root
      4 bash
      3 sync
      3 spool
      3 shutdown

注释:用如上一条命令即可实现了,不过去除所有字母后,用xargs -n1 实现每行一列(n1则表示一列,n2则表示两列);如下;

[root@localhost_002 shell100]# cat 2.txt         #准备一个临时文件:
root:x:bash
bash:root:x
bash:dash:rohtg
[root@localhost_002 shell100]# cat 2.txt|sed 's#[^a-zA-Z]# #g'   #过滤掉2.txt文档里的所有特殊字符;
root x bash
bash root x
bash dash rohtg
#如果|xagrs 内容会在一行显示;并以空格为分隔符;
[root@localhost_002 shell100]# cat 2.txt|sed 's#[^a-zA-Z]# #g'|xargs
root x bash bash root x bash dash rohtg
#如果|xagrs -n1 内容会在每行一列显示;
[root@localhost_002 shell100]# cat 2.txt|sed 's#[^a-zA-Z]# #g'|xargs -n1  #实现每行一列;
root
x
bash
bash
root
x
#如果|xagrs -n2 内容会在每行两列显示;并以空格为分隔符;
[root@localhost_002 shell100]# cat 2.txt|sed 's#[^a-zA-Z]# #g'|xargs -n2   #实现每行两列;
root x
bash bash
root x

注释:如上用 |xargs  让内容再一行显示,并以空格为空格符;

|xargs  -n1 让内容每行 1 列,并以空格为分隔符;

[root@localhost_002 shell100]# cat 2.txt|xargs -n1
root:x:bash
bash:root:x
bash:dash:rohtg

|xargs  -n2让内容每行 2 列,并以空格为分隔符;会把下一行的内容补上来了;以 空格 为分隔符;

[root@localhost_002 shell100]# cat 2.txt|xargs -n2
root:x:bash bash:root:x
bash:dash:rohtg

方法二:当然也可以写成脚本的形式:

[root@localhost_002 shell100]# cat 58.1.sh 
#!/bin/bash
#这个脚本用来计算重复次数;
#日期: 2019-01-18
#作者: yuanhh
for w in `sed 's#[^a-zA-Z]# #g' $1`
do
    echo $w
done |sort|uniq -c|sort -nr|head
运行脚本:
[root@localhost_002 shell100]# sh 58.1.sh 3.txt 
     21 x
     20 sbin
     14 nologin
      8 bin
      6 var
      5 root
      4 bash
      3 sync
      3 spool
      3 shutdown

注释:如上图例,采用传参的方式来执行;    $1 表示获取的的第一个参数了;

4难题:把所有成员平均分成若干个小组,这里,提供一个人员列表,比如成员有50个人,需要分成7个小组,要求随机性,每次执行脚本的结果会不一致;

假设分成7个小组,每个小组7个人,为了实现随机性,可以根据人名的长度来做一个运算,比如用一个随机数加人名的长度得到一个随机数,然后除以 7 取余数,余数是 几 就该把用户分到第几组

考虑到人员数量较少,最终分组一定不均衡,比如有的小组分了10个人,有的小组分到了3个人;为了让人员均衡,需要把人数偏多的组(大于7)均分一部分到人数偏少的组里面;

逻辑:在网上随机着了一写英文用户名:使用cksum用英文名生成的随机数,在加上使用$RANDOM(为了更加随机),再除以 7 ,然后取余数,余数是 几 则分到第几组里;再用  shuf 来打乱人员顺序,保证随机性,然后调用上面的函数(使用cksum用英文名生成的随机数,在加上使用$RANDOM(为了更加随机),再除以 7 ,然后取余数,余数是 几 则分到第几组(临时文件)),然后分别计算每个组(临时文件)有多少行,这样可以指定每个组(临时文件)里有几个人,然后获取到组员人数最多的小组(max函数),然后在获取到组员人数最少的小组(min函数),得到这里这两个函数后,然后还需要求一个平均值(四舍五入函数),保证每个组的相应人数,然后用while把人员多的组的人数搞到人员少的组里面;(条件是:当最小组人员数小于等于7,不在循环,只要不满足该条件,就需要把max组里面的成员放到min组里面,即删除max组里面的最后一名成员,并且把该成员增加到min组里面);

[root@localhost_002 shell100]# wc -l member.txt 
72 member.txt

脚本中用到了一些知识点:  cksum       $RANDOM    shuf

cksum 用来计算随机数:   echo  "ssdsdfsadf"|cksum

[root@localhost_002 shell100]# echo "sdfsadfsd"|cksum
1061990298 10

$RANDOM   :  系统内置的随机数,每次 echo 的值都不一样;              echo   $RANDOM

[root@localhost_002 shell100]# echo $RANDOM
14103
[root@localhost_002 shell100]# echo $RANDOM
28546
[root@localhost_002 shell100]# echo $RANDOM
26255

shuf  : 用来打乱顺序         

[root@localhost_002 shell100]# echo -e "1\n2\n3\n4"|shuf
3
1
4
2

脚本内容

#!/bin/bash
#这个脚本用来给人员分组
#作者:猿课-阿铭 www.apelearn.com
#日期:2018-12-02

#人员列表文件
f=member.txt
#小组数
group_n=7
#人员总数
member_n=`wc -l $f|awk '{print $1}'`

#根据姓名计算该用户所在小组的id
get_n()
{
    #根据姓名计算cksum值
    l=`echo $1|cksum|awk '{print $1}'`
    #获取一个随机数
    n1=$RANDOM
    #cksum值和随机数相加,然后除以小组数取余,这样可以确保每次获取到的余数都不一样
    n2=$[$n1+$l]
    g_id=$[$n2%$group_n]
    #假如小组数为7,则余数范围0-6,如果余数为0,则小组为7
    if [ $g_id -eq 0 ]
    then
        g_id=$group_n
    fi
    echo $g_id
}

for i in `seq 1 $group_n`
do
    #n_$i.txt为临时文件,用来记录该小组内的成员
    #脚本之前执行过,则该文件会存在,本次执行脚本前应该删除掉这个临时文件
    [ -f n_$i.txt ] && rm -f n_$i.txt
done


shuf $f|while read name
do
    #计算用户所在小组的id
    g=`get_n $name`
    #将人员追加写入到他对应的小组里
    echo $name >> n_$g.txt
done

#定义计算文件行数的函数
nu(){
    wc -l $1|awk '{print $1}'
}

#获取组员人数最多的小组
max(){
    ma=0
    for i in `seq 1 $group_n|shuf`
    do
        n=`nu n_$i.txt`
        if [ $n -gt $ma ]
        then
            ma=$n
       fi
    done
    echo $ma
}

#获取组员人数最少的小组
min(){
    mi=$member_n
    for i in `seq 1 $group_n|shuf`
    do
       n=`nu n_$i.txt`
       if [ $n -lt $mi ]
       then
           mi=$n
       fi
    done
    echo $mi
}

#定义四舍五入函数
div()
{
    n=`echo "scale=1;$1/$2"|bc`
    n1=`echo "scale=1;$n+0.5"|bc`
    echo $n1|cut -d. -f1
}

#小组组员平均值(非四舍五入)
ava_n=$[$member_n/$group_n]
#小组组员平均值(四舍五入)
ava_n1=`div $member_n $group_n`

if [ $ava_n -eq $ava_n1 ]
then
    #定义初始最小值
    ini_min=1
    #以下while循环要做的事情,就是要把人数多的组里的人搞到人数少的组里去
    #此while循环的条件是,当人数最少的组成员数小于组员平均值
    while [ $ini_min -lt $ava_n1 ]
    do
        #找出人数最多的组
        m1=`max`
        #找出人数最少的组
        m2=`min`
        for i in `seq 1 $group_n|shuf`
        do
            n=`nu n_$i.txt`
            #找到人数最多的组对应的文件f1(可能有多个,这里取出现的第一个即可)
            if [ $n -eq $m1 ]
            then
                f1=n_$i.txt
            #找到人数最少的组对应的文件f2(可能有多个,这里取出现的第一个即可)
            elif [ $n -eq $m2 ]
            then
                f2=n_$i.txt
            fi
        done
        #取f1中最后一个人名
        name=`tail -n1 $f1`
        #将这个人名追加写入f2中
        echo $name >> $f2
        #在f1中删除刚刚取走的人名
        sed -i "/$name/d" $f1
        #把此时的最少组人员数赋值给ini_min
        ini_min=`min`
    done
else
    #定义初始最大值
    ini_max=$member_n
    while [ $ini_max -gt $ava_n1 ]
    do
        #找出人数最多的组
        m1=`max`
        #找出人数最少的组
        m2=`min`
        for i in `seq 1 $group_n|shuf`
        do
            n=`nu n_$i.txt`
            #找到人数最多的组对应的文件f1(可能有多个,这里取出现的第一个即可)
            if [ $n -eq $m1 ]
            then
                f1=n_$i.txt
                #找到人数最少的组对应的文件f2(可能有多个,这里取出现的第一个即可)
            elif [ $n -eq $m2 ]
            then
                f2=n_$i.txt
            fi
        done
        #取f1中最后一个人名
        name=`tail -n1 $f1`
        #将这个人名追加写入f2中
        echo $name >> $f2
        #在f1中删除刚刚取走的人名
        sed -i "/$name/d" $f1
        #把此时的最少组人员数赋值给ini_min
        ini_max=`max`
    done
fi

for i in `seq 1 $group_n`
do
    echo -e "\033[34m$i 组成员有:\033[0m"
    cat n_$i.txt
    #把临时文件删除
    rm -f n_$i.txt
    echo
done

5、写一个shell脚本,比较两个数的大小,支持浮点数和负数,两个数通过参数的形式传递;

注释:在比较大小时,然后 -gt  -lt  只能支持整数,不支持浮点数和负数;如下所示:

[root@localhost_002 ~]# x=2;y=3
[root@localhost_002 ~]# if [ $x -gt $y ];then echo "2>3";else echo "2<3";fi
2<3
[root@localhost_002 ~]# x=2.1;y=3   #当 x y的值设置的是小数时,则会报错;
[root@localhost_002 ~]# if [ $x -gt $y ];then echo "2>3";else echo "2<3";fi
-bash: [: 2.1: 期待整数表达式
2<3

那么可以 bc 命令来比较, 如果 x > y ,显示结果为 ,如果 x < y,显示结果则为.

[root@localhost_002 ~]# x=2;y=3          #设置 x 和 y 的参数;
[root@localhost_002 ~]# echo "$x>$y"|bc   #如果是 0,则结果是假,不成立;
0
[root@localhost_002 ~]# echo "$x<$y"|bc   #如果是 1,则结果是真,成立;
1

注释:在脚本里需要在考虑到几种情况:然后在比较即可;

1)  判断给出的参数个数是否两个:      if [ $# -ne  2 ]

2)  判断输入的是负数,如果是,则替换会正整数;如果不是,则等于 第一个参数; if  echo  $1|grep -q   '^-'

3)  判断输入的数字是否数字,如果是字母,则列出;    if  echo  $nu|sed 's#[0-9.]##g'

4)  判断输入的数字是否小数点开头,如果是,则列出;  if  echo $1|grep -q '^\.'

[root@localhost_002 shell100]# cat 60.1.sh 
#!/bin/bash
#这个脚本用来比较数字大小
#日期: 2019-01-20
#作者: yuanhh
if [ $# -ne 2 ]
then
    echo "请输入两个参数"
fi
if_number(){
    if echo $1|grep -q '^-'
    then
        nu=`echo $1|sed 's#^-##g'`
    else
    nu=$1
    fi
    n=`echo $nu|sed 's#[0-9.]##g'`
    if [ -n "$n" ]
    then
        echo "$1不是合法数字"
        exit
    fi
    if echo $1|grep -q '^\.'
    then
        echo "$1不是合法数字"
        exit
    fi
}
if_number $1
if_number $2
n1=`echo "$1>$2"|bc`
if [ $n1 -eq 1 ]
then
    echo "$1 > $2"
else
   if [ "$1" == "$2" ]
then
    echo "$1 == $2"
else
    echo "$1 < $2"
   fi
fi

注释:如上脚本支持输入 整数   负数   小数点等;

转载于:https://my.oschina.net/yuanhaohao/blog/3003456

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值