• 搜索
  • 夜间模式
    ©2026  依刻学习 Theme by OneBlog

    依刻学习博客

    搜索
    标签
  • 首页>
  • 学习的一天>
  • 正文
  • 三剑客进阶

    2025年04月25日 11 阅读 0 评论 3401 字

    前言

    练习三剑客,题目来源于牛客的shell在线练习
    这里仅显示我认为比较有难度的

    实践

    1.写一个bash脚本,统计一个文本文件nowcoder.txt中每一行出现的1~5数字的个数,并且计算一下整个文档中一共出现了几个1~5数字的总数

    cat nowcoder.txt|sed  's/[a-zA-Z]//g'|awk 'BEGIN{FS="";sum=0;}{
            num=0;
            for(i=1;i<=NF;i++){
                if($i>=1&&$i<=5){
                    num++
                }
            }
            sum+=num;
            print "line"NR,"number:"num
        }END{
            print "sum is"sum
        }'
    

    刚开始接触这种负载的awk,没写出来,这是借鉴大佬的
    因为需要格式化输出,并且最后需要总结,第一个想到了awk,但是要求数字范围为1-5,所以先使用sed过滤
    原本考虑使用tr但是tr无法使用正则,其实这里后来想想不需要使用sed过滤因为awk无法对字符格式的进行数值计算所以会直接跳过
    awk流程:
    1.因为需要对每个数字单独进行匹配而awk默认只能按照列匹配,所以在BEGIN初始化,设置FS按字符分列,使每个字符一列
    2.行处理,每一行计算数字的数量,结束后输出并汇集到sum中
    3.END最终输出sum

    2.写一个bash脚本以实现一个需求,求输入的一个数组的平均值
    第1行为输入的数组长度N
    第2~N行为数组的元素

    awk 'BEGIN{
        sum=0;
        max=0
    }{
        if(NR==1){
            max=$1
        }else{
            sum+=$1
        }
    }END{
        #print sum/max 精度太高不符合
        printf "%.3f\n",sum/max
    }'
    

    手撕
    第一行获取除数,行内计算获取被除数,最后在END格式化输出

    3.写一个bash脚本以实现一个需求,去掉输入中含有B和b的单词

    #一个错误的想法
    awk '/[^bB]/{print}'
    #这里想输出不含b或B的行,但是却完整输出了,因为想法是错的,实际上只要有不是b或B就输出,就是即使有bB但有其他字符也会输出
    awk '{
        for (i=1; i<=NF; i++) {
            if ($i ~ /.*[bB]+.*/) {
                continue
            } else {
                print $i
            }   
        }
    }'

    4.写一个脚本统计文件nowcoder.txt中的每一行是否是正确的IP地址。
    如果是正确的IP地址输出:yes
    如果是错误的IP地址,且是四段号码的话输出:no,否则的话输出:error
    NF是该行的列数,$NF是该行的最后一列

    awk -F '.' '{
        if(NF!=4){
            print "error"
        } else{
            sign=0;
            for (i=1;i<=4;i++){
                if ($i <=255){
                    contiue;
                }else{
                    sign=1;
                    break;
                }
            }
            if (sign==0){
                print "yes"
            }else{
                print "no"
            }
        }
        }' nowcoder.txt
    

    首先判断是否是4段号码,否则直接error,其次再通过对每个字段的内容判断是否符合IP形式

    5.将文件nowcoder.txt中每一行的字段逆序输出,其中字段之间使用英文冒号:相分隔。
    假设nowcoder.txt内容如下:
    nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
    root:*:0:0:System Administrator:/var/root:/bin/sh

    #print默认会换行,printf默认不会换行
    awk 'BEGIN{
        FS=":";OFS=":"
        }{
            for(i=NF;i>0;i--){
                printf $i
                if(i!=1){
                    printf ":"
                }
            }
            print '\n'
        }'

    发现其中的OFS其实是没有用的,其原因是OFS只有在print $1,$2,$3 连续输出时才会有用

    6.假设有一些域名,存储在nowcoder.txt里,现在需要写一个shell脚本,将域名取出并根据域名进行计数排序处理(降序)。
    假设nowcoder.txt内容如下:
    http://www.nowcoder.com/index.html
    http://www.nowcoder.com/1.html
    http://m.nowcoder.com/index.html

    cat nowcoder.txt|grep -oP '(?<=http://)\S+\.\S+\.(com|cn|io)' |sort |uniq -c|sort -r|awk '{print $1,$2}'
    #这里要求输出格式前没有空格,但是uniq输出是有空格的,使用awk重新输出

    7.打印只有一个数字的行
    假设nowcoder.txt内容如下:
    haha
    1
    2ab
    cd
    77

    cat nowcoder.txt|awk 'BEGIN{
        FS=""
    }{
        max=0
        for(i=1;i<=NF;i++){
            if($i ~ /[0-9]/){
                max++
            }
        }
        if(max==1){
            print $0
        }
    }'

    8.文件nowcoder.txt,里面的每一行都是一个数字串,编写一个shell脚本对文件中每一行的数字串进行格式化:每3个数字加入一个逗号(,)。
    例如:数字串为“123456789”,那么需要格式化为123,456,789。

    cat nowcoder.txt|awk 'BEGIN{
        FS=""
    }{
        for(i=1;i<NF;i++){
            printf $i
            if(i%3==NF%3){
                printf ","
            }
        
        }
        print $NF
    }'

    这里有个比较困难的就是逗号每隔3个出现的起点是数字末尾而不是开头,例如1,234,567,所以这里我使用i%3==NF%3进行判断

    本文著作权归作者 [ wymm ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    取消回复

    发表留言
    回复

    Copyright©2026  All Rights Reserved.  Load:0.021 s
    Theme by OneBlog V3.6.5
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。