Shell scripting newbie problem

I am trying to create a shell script similar to ls, but which only lists directories. I have the first half working (no argument version), but trying to make it accept an argument, I am failing. My logic is sound I think, but I'm missing something on the syntax, I'm guessing in the bolded line? Any help would be greatly appreciated, thanks!

if [ $# -eq 0 ] ; then
    d=`pwd`
    for i in * ; do
        if test -d $d/$i ; then
            echo "$i:"
        fi
    done
else
    if [ $# -eq 1 ] ; then
        d=$1
        for i in * ; do
            if test -d $d/$i ; then
                echo "$i:"
            fi
        done
    fi
fi
ls -l |grep ^d

find . -type d 

rdc, I know there are probably better tools, but this is an assignment I'm stuck with. :-/

Thanks for the quick reply though!

are you passing the absolute path as argument ?

what error you are getting ?

No, I'm not passing the absolute path, just the same type of argument you'd pass "ls" for example.

I've tried using "~" "/" and "..." as arguments... I think I even tried the absolute path once (but can't remember for sure).

If you want to check the passed argument is a directory or not by using

if test -d $1 ; then
     echo "$i:"
fi
[ -d $1 ] && echo "$1 is directory" || echo "$1 is not directory"

No, the goal is to check if the contents (of the argument directory) are directories or not. I got it working with this code below, but what I don't understand is why the for/if notation I used in the top (no argument version) had to be changed so much for the bottom (argument version). I guess I'm not sure exactly what "i in *" (in the top version) is iterating over. How does it define *?

if [ $# -eq 0 ] ; then
    d=`pwd`
    for i in * ; do
        if test -d "$d"/"$i" ; then
            echo "$i:"
        fi
    done
else
    if [ $# -eq 1 ] ; then
        d="$1"
        for i in "$d"/* ; do
            if test -d "$i" ; then
                echo "${i##*/}:"
            fi
        done
    fi
fi

for i in *

is used to iterate all the files and directories inside the current direcotry ( from where you running this loop)

for i in "$d"/*

is used to iterate all the files which is inside the $d

1 Like

The problem in your script is that you are not switching to the directory passed in on the command line. You are examining all files in the current directory but prepending the parameter.

From your script:

else
    if [ $# -eq 1 ] ; then
        d=$1
        for i in * ; do   #this lists all files in the current directory
            if test -d $d/$i ; then   #$d/$i might not exist because $i is in the pwd and may not be in $d
                echo "$i:"
            fi
        done
    fi
fi

Easiest solution, is to cd to the desired directory and then run your loop, leaving the $d/ out of the test. And don't forget to test that the directory switch worked and issuing an error if it doesn't --- there's nothing to prevent the user from putting a regular file on the command line.

Since this seems like an assignment, I'm not offering any code.

---------- Post updated at 23:24 ---------- Previous update was at 23:22 ----------

Looks like a few of us crossed posts. Glad you figured it out, and you should have some meaningful explanation now too.

1 Like

Yes, the explanation given in your post and the one above were what I needed.

+thanks to all that helped! :b:

---------- Post updated at 10:50 PM ---------- Previous update was at 09:31 PM ----------

You're right, it is an assignment, but I'm actually more interested in learning than in "just" getting it done. Even though I had it working with the code I posted earlier in post #7 (changing "for i in " to "for i in $d/"), I still am trying to find the most efficient way to do it.

Which is why I appreciate your alternate suggestion above of cd'ing before looping. Funny thing is that I had that thought myself hours before frustration led me to post here... but for whatever reason I didn't try to implement it, or didn't think it would work. But now that you've suggested it, it reminded me I had it, so I tried it out. It is literally as easy as taking the top loop and adding 2 extra lines ("cd $1" before the loop and "cd -" after it). Grr... a 5-second solution that I couldn't find earlier after two hours racking my brains. Oh well, at least I got it working two different ways now. :smiley: Thanks again!

EDIT: and you're right I should add a conditional to check it is actually a directory... will get on that soon too!

if [ $# -eq 0 ] ; then
    d=`pwd`
    for i in * ; do
        if test -d "$d"/"$i" ; then
            echo "$i:"
        fi
    done
else
    if [ $# -eq 1 ] ; then
        cd $1
        d=`pwd`
        for i in * ; do
            if test -d "$d"/"$i" ; then
                echo "$i:"
            fi
        done
        cd -        
    fi
fi