第二章: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",使用了大括號,經測試不用也同樣行。有的時候,像這種大括號、雙引號使用與否皆可的狀況,確實讓人以爲很困擾。

相關文章
相關標籤/搜索