2014-04-19 368 views
1

我必須遞歸地搜索所有子目錄並打印*(*號的深度=文件/目錄的深度)類型和名稱。問題出現在我輸入目錄然後想離開但沒有任何反應時。從遞歸返回的bash

我的測試文件

DIR test 
*FILE ace 
*FILE base 
*DIR father 
**FILE cookies 
*DIR mother 
**DIR how 
***FILE youdoing 
*FILE zebra 

我的代碼

MAXDEPTH是多遠到DIR可以去(默認值3)和currDepth開頭

function tree(){ 
     maxDepth=$2 
     currDepth=$3 
     #print the starting file 
     if [ "$currDepth" -eq 0 ];then 
      printf "%s %s\n" DIR "$1" 
      currDepth=1 
     fi 
     for path in "$1"/*;do 
      for i in $(seq 1 $currDepth);do  
       echo -n * 
      done 
      if [ -d "$path" ];then 
       printf "%s %s\n" DIR "${path##*/}"   
       if [[ "$currDepth" -lt "$maxDepth" ]];then 
        tree "$path" "$maxDepth" "$((currDepth + 1))" 
       fi 
       continue 
      fi 
      if [ -f "$path" ];then  
       printf "%s %s\n" FILE "${path##*/}" 
       continue 
      fi 
      if [ -L "$path" ];then 
       printf "%s %s\n" LINK "${path##*/}" 
       continue    
      fi 
     done 
    } 

是1我輸出

DIR test 
*FILE ace 
*FILE base 
*DIR father 
**FILE cookies 
**DIR mother 
***DIR how 
***FILE zebra 

我在做什麼錯了

+1

你做錯了一件事是你應該使用find命令 – Kevin

+0

它特別說我應該使用遞歸 – TheGuyWithStreetCred

+1

這個函數不是遞歸的。它不會調用'tree',它只是調用'printf tree ...'。 – kojiro

回答

1
  1. 在運行之前先調試腳本set -x
  2. 通過用整數屬性-i來確定整數總是整數。
  3. 一致地使用表達式語法。如果您的目標shell是bash,那麼總是使用[[ ]]測試進行字符串比較以及(())進行算術和數字比較是一個好主意。
  4. 使用(())代替seq代替循環,這是非標準的。
  5. 在函數中明確聲明變量(使用localdeclare)以確保它們的作用域是函數的範圍。
  6. 其實打電話給內線tree

#!/bin/bash 
tree() { 
    local -i maxDepth=$2 # Make sure these values are always integers 
    local -i currDepth=$3 

    # print the starting file 
    if ((currDepth == 0)); then # use bash arithmetic 
     printf "%s %s\n" DIR "$1" 
     currDepth=1 
    fi 
    for path in "$1"/*;do 
     for ((i=0; i<currDepth; i++)); do 
      printf '*' 
     done 
     if [[ -d "$path" ]];then 
      printf "%s %s\n" DIR "${path##*/}"   
      if [[ "$currDepth" -lt "$maxDepth" ]];then 
       tree "$path" "$maxDepth" "$((currDepth + 1))" 
      fi 
      continue 
     fi 
     if [[ -f "$path" ]];then  
      printf "%s %s\n" FILE "${path##*/}" 
      continue 
     fi 
     if [[ -L "$path" ]];then 
      printf "%s %s\n" LINK "${path##*/}" 
      continue    
     fi 
    done 
} 
+0

修正了語法,但遞歸似乎有些問題。就像它甚至沒有返回到開始文件一樣,加上currDepth永遠不會變回1 – TheGuyWithStreetCred

+0

@ user2202368:'1。在運行之前通過設置-x來調試腳本。你嘗試過嗎?祝你好運。 – shellter

+0

我現在正在做的,這些繼續 - s是可疑的 – TheGuyWithStreetCred

1

這裏的解決方案前本地和sed:

find <DIR> -exec stat --printf="%n,%F\n" "{}" \; | \ 
sed -r -e "s/[^\/]+\//\*/g" -e "s/regular file/FILE/" -e "s/directory/DIR/" | \ 
sed -r -e "s/([\*]+)([^,]+),(.+)/\1 \3 \2/" 

重要:使用DIR沒有DIR /否則DIR名稱不會出現在結果中。

說明:

find回報遞歸DIR內的所有文件和目錄。

-execfind中的選項允許將每個結果傳遞給另一個命令。 在這裏,我通過每個結果的命令stat

stat有一個選項來格式化輸出-printf(見手冊頁):

  • %n是文件名(與relavtive路徑)
  • %F是文件類型(常規文件,目錄,符號鏈接,塊特殊文件...)

所以,

find <DIR> -exec stat --printf="%n,%F\n" "{}" \;

返回以下,一個結果由線(假設只有常規文件和目錄DIR):

DIR/path/to/file,regular file 
DIR/path/to/dir,directory 

然後,我使用SED改造每行的路你需要使用正則表達式:

  1. 通過*更換string/ - >***basename,file type
  2. 通過FILE
  3. 更換"regular file"通過DIR
  4. 洗牌basenamefiletype使用回引用在sed左右更換"directory"

注意:我不會詳細解釋正則表達式是如何工作的,因爲它會太長。

+0

我有沒有f **國王的想法你在這裏做了什麼,謹慎解釋 – TheGuyWithStreetCred

+0

這是一個解釋的地獄,謝謝 – TheGuyWithStreetCred

+0

@ user2202368你基本上告訴我們在你的問題的意見,你不想使用'find'代替遞歸功能。然後你用'find'接受了一個答案,而不是遞歸函數。那是怎麼回事? – kojiro