2016-10-17 90 views
1

我知道我的後續任務可以使用更簡單的「查找」註釋來完成,但我試圖使用遞歸調用來實現解決方案。我正在查看一個特定的目錄,並試圖在所有子目錄中獲得最大長度的任何文件名。但是,我的遞歸只有一個級別,所以它基本上會返回給我一個特定目錄或其子目錄中最長的文件名。遞歸bash函數(目錄迭代器)

#! /bin/bash 

export maxlen=0 

findmaxr() 
{ 
     if [ $# -eq 0 ] ; then 
     echo "Please pass arguments. Usage: findmax dir" 
     exit -1 
     fi 

     if [ ! -d "$1" ];  then 
     echo "No such directory exist." 
     exit -2 
     fi 

     for file in $(/bin/ls $1) 
       do 
       if [ -d "$file" ] ; then 
         findmaxr $file # Recursively call the method for subdirectories 
       else 
         cur=${#file} 
         if [ $maxlen -lt $cur ] ; then 
           maxlen=$cur 
         fi 
       fi 
       done 

     echo "The file with the longest name has [$maxlen] characters." 



} 

findmaxr `pwd` 

回答

2

這裏有幾個問題。最大的是在[ -d "$file" ]findmaxr $file中,file變量只包含文件的名稱,而不包含整個路徑。因此,如果你在/ dir中,並且/ dir/sub/sub2存在,最高級別將運行findmaxr /dir(這很好),它將運行findmaxr sub(它可以工作,但不是你想要的),它然後運行findmaxr sub2(根本不起作用)。所以一種可能性是在這些行中使用"$1/$file",但還有另一個問題:parsing ls is a bad idea and will fail for some directory names。最好是使用for path in "$1"/*,它沒有解析問題(只要你用雙引號引用所有的變量引用),爲你提供了完整的路徑,所以你不必預先設定$1/。但是,在檢查文件名長度之前,必須先剝離路徑的前端,並使用類似local file="$(basename "$path")"的內容。

第二個問題是,在完成每個目錄後,不是在整個樹被掃描完後纔打印$maxlen。爲了解決這個問題,在運行findmaxr之後,只需將該命令從遞歸函數移出到主序列即可。

還有一個微妙的問題,以及:filecurpath如果你按照我的建議)不是局部變量,這意味着遞歸調用可以改變他們的價值觀聯合國findmaxr調用實例。您應該將它們聲明爲局部變量以避免混淆。哦,不需要導出maxlen - 它會在腳本中自動全局化,並且與您正在運行的任何命令(其中的export傳遞給它)無關。

+0

謝謝。我在其他地方讀到解析ls有問題,但找不到解釋。您提供的信息非常有用! – DR29

2

findmaxr的每個實例都需要返回找到的maxlen(通過echo),您需要在比較中包含該輸出。

還有另一個問題:假設abc是目錄,d.txt是一個文件,並且它們佈置是這樣的:a/b/c/d.txt。從a運行腳本。當fileb時,if [ -d "$file" ]爲真,findmaxr b被調用。它調用ls b,這反過來導致findmaxr c,這導致ls c ...除了ls c失敗,因爲你仍然在a。您需要將cd轉換爲子目錄,否則包含整個路徑,如下所示:$1/$file

這裏是固定的這些問題你的腳本:

#!/bin/bash 

findmaxr() 
{ 
    if [ $# -eq 0 ] ; then 
    echo "Please pass arguments. Usage: findmax dir" 
    exit -1 
    fi 

    if [ ! -d "$1" ];  then 
    echo "No such directory exist." 
    exit -2 
    fi 

    maxlen=0 
    for file in $(/bin/ls "$1") 
      do 
      if [ -d "$1/$file" ] ; then 
        cur=`findmaxr "$1/$file"` # Recursively call the method for subdirectories 
      else 
        cur=${#file} 
      fi 
      if [ $maxlen -lt $cur ] ; then 
       maxlen=$cur 
      fi 
     done 
     echo $maxlen 
} 

maxlen=$(findmaxr $(pwd)) 
echo "The file with the longest name has [$maxlen] characters."