I know that my following task could be accomplished using simpler 'find' comment, but I am trying to implement a solution using a recursive call. I am looking through a specific directory and trying to get max length of any filename in all the sub-directories. However, my recursion works only one level down, so it basically returns me the longest filename in a certain directory or in its' subdirectories.

#! /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`
share|improve this question
    
can you add some echo statement for debugging purpose and see where it fails. – Kamaraj Oct 17 '16 at 2:39

Try:

#! /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 "$1"/*
                do
                if [ -d "$file" ] ; then
                        findmaxr "$file"   # Recursively call the method for subdirectories
                else
                        f=${file##*/}
                        cur=${#f}
                        if [ $maxlen -lt $cur ] ; then
                                maxlen=$cur
                        fi
                fi
                done
}

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

Discussion

Don't do this:

for file in $(/bin/ls $1)

Even if no file name contains whitespace, parsing ls is still unreliable.

By contrast, this will work reliably:

for file in "$1"/*

Further, this form will keep around the names of the parent directories which is what you need to descend into subdirectories. For example, using the directory structure in the example below, the output of ls shows just the bare file names for the directory d 1:

$ ls 'd 1'
12345  d 2

By contrast, the output of 'd 1'/* includes the names of the parent directory in the output:

$ echo 'd 1'/*
d 1/12345 d 1/d 2

It is by keeping the parent directory names that we make the recursion work.

Since file now contains the full path, we need to strip the directory names off before we determine its length. This is done with prefix removal:

f=${file##*/}

Example

Consider this file structure:

$ find .
.
./d 1
./d 1/12345
./d 1/d 2
./d 1/d 2/1234567
./d 1/d 2/d 3
./d 1/d 2/d 3/123456789
./script

Now, let's run our script:

$ bash script 
The file with the longest name has [9] characters.
share|improve this answer
    
(1) Hmmm. I’m not sure you need to export maxlen. (Yes, I know you copied it from the question, but you fixed other things.) (2) You should probably quote "$maxlen" and "$cur", or else use a test construct (e.g., [[]]?) that makes that unnecessary. (3) You preserved the OP’s general algorithm, which implements one interpretation of the problem.  I would interpret “max length of any filename” to include the names of the directories, and so I would not do else under if [ -d "$file" ], but rather do the cur and maxlen stuff unconditionally. – G-Man Oct 17 '16 at 7:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.