Reputation: 1458
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
Upvotes: 1
Views: 111
Reputation: 451
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:
string/
by *
-> ***basename,file type
"regular file"
by FILE
"directory"
by DIR
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.
Upvotes: 1
Reputation: 77107
set -x
before you run it.-i
integer attribute.[[ ]]
tests for string comparisons and (( ))
for arithmetic and numeric comparisons, if your target shell is bash.(( ))
for loops instead of seq
, which is nonstandard.local
or declare
) to ensure they are scoped to the function.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
}
Upvotes: 1