Question

I have to search all subdirs recursively and print *(number of * = depth of file/dir) type and name. The problem comes when i enter dir and then want to get out but nothing happens.

my test file

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

my code

maxDepth is how far in to the dir it can go(default 3) and currDepth is 1 at the beginning

    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
  }

my output

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

what am i doing wrong

Was it helpful?

Solution 3

I should have used local in front of currDepth=$3

OTHER TIPS

  1. Debug your script by doing set -x before you run it.
  2. Make sure integers are always integers by declaring them with the -i integer attribute.
  3. Use expression syntax consistently. It's a good idea to always use [[ ]] tests for string comparisons and (( )) for arithmetic and numeric comparisons, if your target shell is bash.
  4. Use (( )) for loops instead of seq, which is nonstandard.
  5. Explicitly declare your variables in the function (using local or declare) to ensure they are scoped to the function.
  6. Actually call the inner 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
}

Here a solution using find, stat and 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/"

IMPORTANT: Use DIR not DIR/ otherwise DIR name will not appear in results.

Explanation:

find returns recursively all files and directory within DIR.

-exec option in find allows to pass each result to another command. Here I'm passing each result to the command stat

stat has an option to format the output -printf (see manpage) :

  • %n is the filename (with relavtive path)
  • %F is the file type ( regular file, directory,symbolic link,block special file...)

So,

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

returns the following, one result by line (assuming that there are only regular files and directories in DIR) :

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

Then, I'm using sed to transform each line the way you required using regular expression:

  1. Replace string/ by * -> ***basename,file type
  2. Replace "regular file" by FILE
  3. Replace "directory" by DIR
  4. Shuffle around basename and filetype using back referencing in sed.

NOTE: I will not explain in details how regular expressions work as it would be too long.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top