zoukankan      html  css  js  c++  java
  • Linux shell 学习笔记(二)

    实战!

    指定一个目录,输出该目录下所有文件个数,文件大小之和,以及<=4096字节的文件大小之和及个数,目录名称通过参数传给shell脚本。
     

    第一次尝试!

    ###############
    # Date: 2017-03-02
    # Version: V1.0
    # Author: lizp
    # Usage: FileInfoCount
    ################
    
    if [ -d $1 ]
    then
      ls $1 -lR | awk 'BEGIN {size=0;count=0;Vsize=0;Vsize=0;} {if($5 != ""){size=size+$5;count=count+1;if($5 <= 4096){Vsize=Vsize+$5;Vcount=Vcount+1;}}} END{print "size is", size, "
    count is", count, "
    Vsize is",Vsize,"
    Vcount is", Vcount}'
    else
        echo "input path does not exist"
        exit
    fi

    shell脚本的if语句中, “-d”之前必须有空格,“$1”之后必须有空格,if后面必须有空格

    -d 如果$1为目录,则“-d $1”为真。

    ls -lR  展示输入目录下的所有的文件及文件夹(包含子目录及子目录下的文件夹)。

    *** | awk 'BEGIN{} {} END{}'   将“***”中的记录按照换行符“ ”分割,然后逐条执行:先执行BEGIN段中的部分,然后执行中间大括号中的内容,执行完成后,执行END中的部分。

    运行:

    FileInfoCount.sh  /mydir

    运行结果:

    size is 15727 
    count is 7 
    Vsize is 15727 
    Vcount is 7
    

      结果:题目要求是统计当前目录下所有子目录中的文件的个数,不包括文件夹!

    第二次尝试!

     既然要求只统计目录下的文件个数,就用递归吧,思路很简单,实现起来却很复杂。

    #########################################################################################################################
    # Date: 2017-03-02
    # Version: V1.0
    # Author: lizp
    # Usage: FileInfoCount
    #########################################################################################################################+
    size=0
    count=0
    Vsize=0
    Vcount=0
    
    fileInfo()
    {
        echo "file Info Process begin..."
        size=`ls $1 -l | awk '{printf "%ld
    ", v1+$5}' v1=$size`
        count=`ls $1 -l | awk '{printf "%ld
    ", v1+1}' v1=$count`
        Vsize=`ls $1 -l | awk '{if($5 <= 4096){printf "%ld
    ", v1+$5}}' v1=$Vsize`
        Vcount=`ls $1 -l | awk '{if($5 <= 4096){printf "%ld
    ", v1+1}}' v1=$Vcount`
        resultDisplay
        echo "file Info Process end..."
    }
    
    doOneProcess()
    {
        echo "process begin, path is $1"
        ls $1 | grep -v "match: no file" |while read filename
        do
          filepath="$1""/""${filename}"
          echo $filepath
          
          if [ -d $filepath ]
            then
              doOneProcess $filepath
            else
                fileInfo $filepath
            fi
        done
        resultDisplay
        echo "process end..."
    }
    
    resultDisplay()
    {
        echo "size is" $size
      echo "count is" $count
      echo "Vsize is" $Vsize
      echo "Vcount is" $Vcount
    }
    
    
    if [ -d $1 ]
    then
      if [ -z $1 ]
      then
        path=`pwd`
      else
          path=$1
      fi
      
      doOneProcess $path
      resultDisplay
    else
      echo "input path does not exist"
      exit
    fi

    跑了下,结果却是错的!

    分析原因:管道内的全局变量是不会返回给管道入口的程序的,换句话说,进入管道后,全局变量会复制一份给子进程,然后无论在子进程里值如何变化,在父进程中的值还是原来的模样,因为管道传的是值,不是传址。

    最终

    咨询导师,发现可以用find命令,很简单的就可以实现!

    #########################################################################################################################
    # Date: 2017-03-02
    # Version: V1.0
    # Author: lizp
    # Usage: FileInfoCount
    #########################################################################################################################+
    if [ -d $1 ]
    then
       find $1 -type f -ls | awk 'BEGIN {size=0;count=0;Vsize=0;Vsize=0;} {if($7 != ""){size=size+$7;count=count+1;if($7 <= 4096){Vsize=Vsize+$7;Vcount=Vcount+1;}}} END{print "size is", size, "
    count is", count, "
    Vsize is",Vsize,"
    Vcount is", Vcount}'
    else
        echo "input path does not exist"
        exit
    fi

    哇!原来这么简单!shell真的博大精深!还有很长的路要走啊。。。

    可是,用find命令可以实现,那么用递归就不行了吗?管道不能回传全局变量,这个问题就无解了吗?

    于是我又尝试用临时文件来存放管道输出变量,实现方式如下:

    #########################################################################################################################
    # Date: 2017-03-02
    # Version: V2.0
    # Author: lizp
    # Usage: FileInfoCount
    #########################################################################################################################+
    
    tmpoutfile="/tmp/file_$$"
    
    fileInfo()
    {
        fileSize=`ls $1 -l | awk '{print $5}'`
        echo $fileSize >> $tmpoutfile
    }
    
    doOneProcess()
    {
        ls $1 | grep -v "match: no file" |(while read filename
        do
          filepath="$1""/""${filename}"
          
          if [ -d $filepath ]
            then
              doOneProcess $filepath
            else
                fileInfo $filepath
            fi
        done)
    }
    
    resultDisplay()
    {
      if [ -f $tmpoutfile ]
      then
      cat $tmpoutfile | awk  'BEGIN{size=0;count=0;Vsize=0;Vcount=0;} {size=size+$1;count=count+1;if($1 <= 4096){Vsize=Vsize+$1;Vcount=Vcount+1;}} END{printf("size is %s,count is %s,Vsize is %s,Vcount is %s
    ",size,count,Vsize,Vcount)}' 
      fi
    }
    
    
    if [ -d $1 ]
    then
      if [ -z $1 ]
      then
        path=`pwd`
      else
          path=$1
      fi
      
      doOneProcess $path
      resultDisplay
    else
      echo "input path does not exist"
      exit
    fi

    成功了,输出结果如下:

    /$test.sh
    size is 8090,count is 5,Vsize is 8090,Vcount is 5

    其中size和count为当前目录下的文件(不包含文件夹)的总大小及数量,Vsize和Vcount为当前目录下的文件(不包含文件夹)中,大小<=4096的文件的总的大小及个数。

    这样一来,我就有了两种解决方法:

    1. 通过find命令直接罗列出所有文件,用awk进行计算。

    2. 通过ls命令罗列出所有文件及文件夹,通过递归的方式进行处理,为了防止管道中运算得到的变量丢失,其中管道的输出结果会输出到一个临时文件中去,最后通过awk去计算临时文件中记录的数据,得出结果。

  • 相关阅读:
    shell十三问?
    OS + Linux nmon / nmon analyser / nmon_analyser_v52_1.zip
    nGrinder windows agent / linux agent
    java Base64
    SearchServer Elasticsearch Cluster / kibana
    db mysql / mysql cluster 5.7.19 / my.cnf / thread_pool_stall_limit
    Mininet与真实网络链接的方法
    Install ProcessMaker 3.1 or 3.2 in CentOS/RHEL 7
    软件版本GA,RC,alpha,beta,Build 含义
    paper-9-Research and Implementation of MultiPath TCP on Mobile Smart Deviceses
  • 原文地址:https://www.cnblogs.com/lzp666/p/6496610.html
Copyright © 2011-2022 走看看