实战!
第一次尝试!
############### # 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去计算临时文件中记录的数据,得出结果。