[comp.sources.wanted] Unix "Tree" Command Wanted

georgeb@fai.UUCP (George Bosworth) (08/01/90)

I'm looking for a Unix version of the DOS "tree" command,
that makes a hierarchal list of subdirectories.  Not hard
to write, of course, but hoping not to spend the time.
Thanks for source or pointer to same, by email.

George Bosworth                    uunet!fai.com!georgeb
Fujitsu America, Inc.

bruceb@telesoft.com (Bruce Bergman @quasar) (08/02/90)

In article <2899@fai.UUCP>, georgeb@fai.UUCP (George Bosworth) writes:
> I'm looking for a Unix version of the DOS "tree" command,
> 
> George Bosworth                    uunet!fai.com!georgeb

Here's the puppy.  It's not great, but it does the trick.  It's intended
for BSD.  Just do a "cc -o tree tree.c" and you'll be set.  Have fun!

bruce

----- cut here -----
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/param.h>

#define TRUE		1
#define FALSE		!TRUE

int display_files = FALSE;

/*
*
* Tree.c -- Mimic the DOS tree command
*
* By Bruce A. Bergman, 8767 Dalewood Avenue, San Diego, CA.  92123-3926
*    bruceb@telesoft.com  (619) 457-2700 x123
* 
* Modification History
*
* Who  What       Where
* ---  ---------  -----
* bab  18-Jan-88  Initial creation.
*
* Released into the public domain as long as authorship remains intact.
*
*/

main(argc, argv)
int argc;
char *argv[];
{

	char	path[MAXNAMLEN+1];

	if (argc <= 2) {
		if (argc == 2) {
			if (strncmp(argv[1], "-f", 2) == 0) {
				display_files = TRUE;
				start_at(getwd(path));
			}
			else {
				start_at(argv[1]);
			}
		}
		else {
			start_at(getwd(path));
		}
	}
	else {
		while (--argc > 0) {
			++argv;
			if (strncmp(*argv, "-f", 2) == 0) {
				display_files = TRUE;
				continue;
			}
			strcpy(path, *argv);
			start_at(path);
			display_files = FALSE;
			if (argc > 1) {
				printf("\n");
			}
		}
	}

}

start_at(path)
char *path;
{

	DIR		*fd;

	if ((fd = opendir(path)) == NULL) {
		fprintf(stderr, "%s is not a directory\n", path);
		return;
	}

	report(path, fd);

	closedir(fd);

}

traverse(base, dir)
char *base, *dir;
{

	DIR		*fd;
	char	*p;
	int		b_len,
			d_len;

	if ((strcmp(dir, ".") == 0) || (strcmp(dir, "..") == 0)) {
		return;
	}

	b_len = strlen(base);
	d_len = strlen(dir);

	if ((p = (char *)malloc(b_len+d_len+2)) == 0) {
		fprintf(stderr, "malloc failure in traverse\n");
		exit(0);
	}

	strcpy(p, base);
	*(p+b_len) = '/';
	strcpy(p+b_len+1, dir);
	*(p+b_len+d_len+1) = '\0';

	if ((fd = opendir(p)) != NULL) {
		report(p, fd);
		closedir(fd);
	}

}

report(path, fd)
char *path;
DIR *fd;
{

	struct direct *buf;
	struct stat   sbuf;
	char	*p;
	int		len,
			got_one;

	len = strlen(path);

	if ((p = (char *)malloc(len+MAXNAMLEN+2)) == 0) {
		fprintf(stderr, "malloc failure in report\n");
		exit(0);
	}

	strcpy(p, path);
	*(p+len) = '/';

	printf("Path: %s\n", path);
	printf("Sub-directories: ");

	got_one = FALSE;

	while ((buf = readdir(fd)) != NULL) {
		buf->d_name[buf->d_namlen] = '\0';
		if ((strcmp(buf->d_name, ".") == 0) || (strcmp(buf->d_name, "..") == 0)) {
			continue;
		}
		strcpy(p+len+1, buf->d_name);
		if (stat(p, &sbuf) == -1) {
			continue;
		}
		if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
			if (got_one == FALSE) {
				got_one = TRUE;
				printf("%s\n", buf->d_name);
			}
			else {
				printf("                 %s\n", buf->d_name);
			}
		}
	}

	if (got_one == FALSE) {
		printf("None\n");
	}

	if (display_files == TRUE) {
		printf("Files: ");

		got_one = FALSE;
		rewinddir(fd);

		while ((buf = readdir(fd)) != NULL) {
			buf->d_name[buf->d_namlen] = '\0';
			if ((strcmp(buf->d_name, ".") == 0) || (strcmp(buf->d_name, "..") == 0)) {
				continue;
			}
			strcpy(p+len+1, buf->d_name);
			if (stat(p, &sbuf) == -1) {
				continue;
			}
			if ((sbuf.st_mode & S_IFMT) != S_IFDIR) {
				if (got_one == FALSE) {
					got_one = TRUE;
					printf("%s\n", buf->d_name);
				}
				else {
					printf("       %s\n", buf->d_name);
				}
			}
		}

		if (got_one == FALSE) {
			printf("None\n");
		}
	}

	printf("\n");

	rewinddir(fd);

	while ((buf = readdir(fd)) != NULL) {
		buf->d_name[buf->d_namlen] = '\0';
		traverse(path, buf->d_name);
	}

}
----- cut here -----


-- 
att!   \   crash!--\            TeleSoft (bruceb@telesoft.com)
ncr-sd! \           \           5959 Cornerstone Court West
         >--ucsd!---->--telesoft!bruceb (Bruce Bergman N7HAW)
nosc!   /           /           San Diego, CA.  92121-9891
ucbvax!/   uunet!--/            (619) 457-2700 x123
All opinions are my own.    Have you hugged your horse lately?

georgeb@fai.UUCP (George Bosworth) (08/11/90)

In article <2899.UUCP> I asked for a UNIX version of the DOS 
"tree" command.

Many responders didn't know, or had forgot, that the DOS "tree"
command produces an INDENTED subdirectory tabulation, wherein each
deeper level of subdirectory is indented further to the right,
to give instant visualization of the hierarchy. The frequently-suggested
UNIX commands *find*, *ls -R*, and *du* produce only columnar ouput.

Several responders sent C programs or shell scripts that did some
flavor of indented hierarchal directory tabulation, or offered or
pointed to programs or scripts, including lengthy C programs available
by UUCP as uunet!/usr/spool/ftp/comp.sources.misc/volume9/dtree.Z and
uunet!/usr/spool/ftp/comp.sources.unix/volume15/vtree.Z.

One respnder sent a uvtree2 Bourne shell script that was published
by Ray Swartz in the June 1989 Unix Review.  It worked well.  Following
this up, I saw a dtree Bourne shell script published by Ray in the
October issue.  It works well and is extremely compact:

:
# @(#) dtree -- Visual display of directory trees
# Author: Unknown
USAGE="Usage: $0 [starting-directory-name]"
case $# in
    0) startdir="." ;;       #If no param, start at dot
    1) if [ ! -d $1 ]; then  #Single param; directory?
          echo "\"$1\" not a directory." >&2
          echo $USAGE >&2
          exit  1
       fi
       startdir=$1 ;;    #Use single param as start
    *) echo $USAGE >&2   #Multiple params
       exit 2 ;;
esac
(cd $startdir; pwd)      #In subshell, print start name
find $startdir -type d -print | sort -f |   #Find, sort names
sed -e "s,^$startdir,," \
-e "/^$/d" \
-e "s,[^/]*/\([^/]*\)$,\|----\1," \
-e "s,[^/]*/,|    ,g"

Here is a sample run:
pwd
/fai/ddd/georgeb
dtree
/fai/ddd/georgeb
|----Keep
|----News
|----Present
|    |----Big
|    |    |----Filed
|    |    |----Working
|    |----Small
|----Pthread
|----Recruit
|----Uunet
 
George Bosworth                          georgeb@fai.com
Fujitsu America Inc.                     uunet!fai.com!georgeb