1#! /bin/bash 2# 3# original from: 4# vtree: visual directory tree 5# @(#) vtree.sh 1.1 91/07/01 6# 90/04 john h. dubois iii (john@armory.com) 7# 91/07/01 fixed bug that caused problems when dir given on command line, 8# added some info to help, changed to 4-space indenting 9# 10# conversion to bash v2 syntax done by Chet Ramey 11# 12help=\ 13"Syntax: vtree [startdir] [namelen=#] [linelen=#] 14If startdir is not specified, tree will start at current dir. 15 16namelen specifies the minimum number of characters of a directory name that 17are guaranteed to be printed. 18This is a tradeoff between the number of tree levels that can fit on a 19screen line and the number of chars of each dir name that can be printed. 20In most cases it will be possible to print more than namelen characters of 21the name (a name up to namelen+1 chars will always be printed in full), 22but in some cases truncation down to namelen chars will occur. 23If truncation occurs, a '>' is printed at the end of the name. 24namelen=8 (the default) typically causes about 5 dirs/1000 to be truncated. 25namelen=7 typically causes about 10 dirs/1000 to be truncated. 26namelen=8 will allow 6 full length dirs to be printed in 79 columns. 27namelen=7 will allow 7 full length dirs to be printed in 79 columns; 28 29linelen specifies the maximum number of characters to print on one screen 30line. All characters beyond this are truncated. The default is 1024. 31To avoid line wrap on an 80 column terminal with autowrap, use linelen=79. 32" 33 34for i in "$@"; do 35 case $i in 36 -h) echo "$help"; exit;; 37 *=*) 38 vars="$vars $i" 39 ;; 40 *) 41 if [ ! -x $i ] || [ ! -d $i ]; then # arg must be a dir and executable 42 echo "$i: directory not accessible." 43 exit 44 fi 45 cd $i 46 ;; 47 esac 48 shift 49done 50 51pwd # print path of root of tree 52 53# find all directories depth first; ignore permission errors 54find . -type d -print 2> /dev/null | \ 55gawk -F/ ' 56 57# Do this block for NR == 1 instead of BEGIN because command line var 58# assignments are not done until after BEGIN block is executed. 59NR == 1 { 60 if (namelen) 61 MaxLen = namelen; 62 else 63 MaxLen = 8; 64 if (!linelen) 65 linelen = 1024 66 HSpace = substr(" ",1,MaxLen); # used to indent tree 67 n = 0; # number of dirs found on one major branch 68} 69 70$0 != "." { # do for every line produced by find except tree root dir 71 if (NF == 2 && n > 0) # print major branch whenever a new one starts 72 list(); 73 Depth[n] = NF - 1; # record depth and name of dir 74 Name[n++] = $NF; 75} 76 77END { 78 list() # print last major branch 79} 80 81function list() { 82 Line = Name[0]; # initialize first line of branch to be branch base 83 for (i = 1; i < n; i++) { # for each name in major branch 84 if (Depth[i] == Depth[i-1] + 1) 85 AddHLink(); # if moving deeper into branch, use same line 86 else { 87 print substr(Line,1,linelen); # last line is done; print it 88 Line = ""; # start new line 89 # print indentation, vert links, and vert/horiz links 90 for (d = 1; d < Depth[i] - 1; d++) # for each level of indentation 91 # if a vert. link has been established for this level 92 if (VLink[d]) 93 Line = Line HSpace " | "; 94 else # print empty indentation 95 Line = Line HSpace " "; 96 # Print last part of vert. link 97 if (VLink[d] == i) { 98 VLink[d] = 0; # mark level for no vert link 99 Line = Line HSpace " \\--"; 100 } 101 else 102 Line = Line HSpace " |--"; 103 } 104 Line = Line Name[i]; # Add dir name to line 105 } 106 print substr(Line,1,linelen); # print last line of major branch 107 n = 0; # reset name counter 108} 109 110function AddHLink() { 111 NDepth = Depth[i]; # Depth of this name 112 VLink[NDepth - 1] = 0; 113 # search until a name found at a level less than this one 114 for (j = i + 1; j < n && Depth[j] >= NDepth; j++) 115 # keep track of last name that VLink should connect to 116 if (Depth[j] == NDepth) 117 VLink[NDepth - 1] = j; 118 if (VLink[NDepth - 1]) { 119 NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 1); 120 if (length(NLine) < length(Line)) 121 Line = substr(NLine,1,length(NLine) - 1) ">" 122 else 123 Line = NLine; 124 Line = Line substr("--------------+--", 125 18 - ((NDepth - 1) * (MaxLen + 4) - length(Line))); 126 } 127 else { 128 NLine = substr(Line,1,(NDepth - 2) * (MaxLen + 4) + MaxLen + 3); 129 if (length(NLine) < length(Line)) 130 Line = substr(NLine,1,length(NLine) - 1) ">" 131 else 132 Line = NLine; 133 Line = Line substr("-----------------", 134 1,(NDepth - 1) * (MaxLen + 4) - length(Line)); 135 } 136} 137' $vars 138