第二章:Improving On User Commands--18.显示目录内容

   跳着来,一篇一篇移,很麻烦呀。 linux

   ls命令是Unix命令行的基础,该命令中有一个元素在我而言不得要领:指示目录的大小。当一个目录被列出来的时候,程序要么是列出文件的内容,要么是显示文件数据的1024字节块的数目。一个典型的ls -l的输出以下: git

drwxrwxr-x 2 taylor taylor 4096 Oct 28 19:07 bin

 

   可是,事实上,这些内容并非颇有用处,由于我想要知道的是给定目录中有多少个文件。这就是这个脚本要达到的目的,生成一个漂亮的多层文件、目录列表,同时显示了文件大小或是目录中的文件数。 shell

代码: 编程

#!/bin/sh
 
 # formatdir.sh -- 输出一个界面友好、功能有效的目录列表
 
 gmk()
 {
     # 输入单位Kb,输出单位Kb,最大的单位是Gb
     if [ $1 -ge 1000000 ]; then
         echo "$(scriptbc.sh -p 2 $1 / 1000000)Gb"
     elif [ $1 -ge 1000 ]; then
         echo "$(scriptbc.sh -p 2 $1 / 1000)Mb"
     else
         echo "${1}Kb"
     fi
 }
 
 if [ $# -gt 1 ]; then
     echo "Usage: $(basename $0) [dirname]" >&2
     exit 1
 elif [ $# -eq 1 ]; then
     cd "$@"
 fi
 
 for file in *
 do
     if [ -d "$file" ]; then
         size=$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')
         if [ $size -eq 1 ]; then
             echo "$file ($size  entry)|"
         else
             echo "$file ($size  entries)|"
         fi
     else
         size="$(ls -sk "$file" | awk '{print $1}')"
         echo "$file ($(gmk $size))|"
     fi
 done | \
     sed 's/ /^^^/g' | \
     xargs -n 2 | \
     sed 's/\^\^\^//g' | \
     awk -F\| '{printf "%-39s %-39s\n", $1, $2}'
 
 exit 0

脚本如何工做:
这个脚本最有意思的部分就是gmk函数,它会接受一个以kb为单位的数字,输出的单位有kb、mb、gb。它不会让一个文件显示出2083364kb这样的数字,这个函数会显示的是2.08Gb。注意,gmk函数调用时用的是$()方式: 函数

echo "$file ($(gmk $size))|"

由于在$()中的参数会被放到当前脚本运行shell的子shell中,子shell自动继承当前运行的shell中定义的函数。在靠近该脚本顶部位置,还有一个捷径容许用户给定一个目录,而不仅是只能查看当前的目录。它会使用cd命令将当前的工做目录切换到要求的位置。这遵循了优秀shell脚本编程的圣歌: 测试

Where there's a shortcut, there's a better way。

 

这个脚本的主要逻辑部分包含了把脚本输出到平均分布好的2列上。你并不能在输出流中遇到空白时停下来,由于文件或是目录是有可能在它们的名字中包含空白的。为了搞定这个问题,脚本首先用3个脱字符(^^^)替换掉空白。而后使用xargs命令归并2行,这样每2行会变成有一个空白的一行。最后,使用awk命令格式化输出。注意目录中非隐藏的文件数目是很容易计算获得的,只须要用sed清理下wc命令产生的输出: spa

# 很简单的用sed删掉wc产生的输出中的全部非数字字符
# [:digit:] 是POSIX字符类,匹配数字,又好比[:alpha:] 匹配字母
# [^] 表示不匹配任意一个中括号内的字符
# sed 's/...//g' 这个是sed的典型删除句式,由于后面替换的内容是什么也没有
# 有朋友反映,本书中这种句子用的不少,但不大明了,老七就稍微介绍下
  size=$(ls "$file" | wc -l | sed 's/[^[:digit:]]//g')

运行脚本:
若是想看当前目录,那就无参调用本脚本。想看别的任何目录(只要你有这个权限),只须要作为参数传给本脚本便可。 命令行

运行结果: code

formatdir.sh  # 无参调用
-hilow.sh(4Kb)                        ANSIColor.sh(4Kb)                     
countCmds.sh(4Kb)                        filelock.sh(4Kb)                      
fmt.sh(4Kb)                              formatdir.sh(4Kb)                     
hilow.sh(4Kb)                            inpath.sh(4Kb)                        
library.sh(8Kb)                          logrm.sh(4Kb)                         
newnicenum.sh(4Kb)                       newrm.sh(4Kb)                         
normdate.sh(4Kb)                         poorEcho.sh(4Kb)                      
scriptbc.sh(4Kb)                         testLibrary.sh(4Kb)                   
test.sh(4Kb)                             tinyscript.sh(4Kb)                    
unrm.sh(4Kb)                             validAlphaNum.sh(4Kb)                 
validdate.sh(4Kb)                        validfloat2.sh(4Kb)                   
validfloat.sh(4Kb)                       validint.sh(4Kb)                      
validtime.sh(4Kb)                                  

formatdir.sh ~/why/test/  # 别的目录,非当前工做目录
beijing(7entries)                        dir(0entries)                         
gw.sh(12Kb)                              gw.txt(4Kb)                           
heilongjiang(1entry)                     remitcheck(5entries)                  
rmdir(5entries)                          test.sh(8Kb)                          
tmp(4entries)

分析脚本:
GNU版本的ls又一个-h选项,它提供了相似的功能。若是你的机器上是这个版本的ls,那么添加上这个选项,而后删除调用gmk会提升脚本的运行速度。
这个脚本中别的值得思考的特性是你是否恰巧碰上有一个用户特别喜欢在命名一个文件时使用3个脱字符,这会致使在输出时产生异样。不过通常不会碰到。我测试过的linux上的文件,至今未碰到过一例。不过,若是你确实很关心这点,你能够不用3个脱字符,只要用别的不会出如今你的文件名中的字符序列就好了。 orm

ps:

   scriptbc.sh,还记得第九个脚本“一个任意精度浮点计算器”吗?

   函数中使用的参数,都是调用传递给它的参数,而不是从命令行传递给脚本的参数。若是想用命令行参数,能够把命令行参数保存到一个变量中,而后在函数中调用。注意,即便如"$@"这样的调用,在函数中也不是命令行参数。

   本脚本中第13行,echo "${1}Kb",使用了大括号,经测试不用也同样行。有的时候,像这种大括号、双引号使用与否皆可的状况,确实让人以为很困扰。

相关文章
相关标签/搜索