blob: 874e1beb93763f221f154a94387308e355af5ba5 [file] [log] [blame]
#!/bin/sh
# A really simple implementation of find, for those of us without busybox
# or the desire to include the oversized GNU one.
#
# WARNING: the symlink-avoidance feature may have race conditions. Try
# not to use this tool for anything important.
#
usage()
{
echo "Usage: $0 <paths>" >&2
echo " Unlike a real version of 'find', this program has no options." >&2
}
startswith()
{
[ "${1#"$2"}" != "$1" ]
return $?
}
do_find_onedir()
{
local prefix="$1"
# Yes, due to oddities of sh parsing rules, this loop is actually safe
# for filenames containing spaces. (It will also work with filenames
# containing newlines, but find separates output lines with newline, so
# that's still not useful.)
for d in * .*; do
[ "$d" = "." ] && continue
[ "$d" = ".." ] && continue
if [ -L "$d" ] || [ -e "$d" ]; then # skip '*' and '.*' in empty dir
echo "$prefix/$d"
fi
if [ -d "$d" ] && [ ! -L "$d" ]; then
cd "$d" && {
do_find_onedir "$prefix/$d"
cd ..
}
fi
done
}
do_find()
{
for d in "$@"; do
# Normally I would use () instead of {} here, to remove the need for
# the possibly-bug-inducing 'cd ..' step. However, () requires a fork,
# which causes a fairly significant slowdown in this already-slow
# implementation of find.
cd "$d" && {
echo "$d" # find should always print the directory itself first
do_find_onedir "${d%/}"
cd ..
}
done
}
# Check command line validity
for d in "$@"; do
startswith "$d" "-" && usage
done
if [ $# = 0 ]; then
do_find .
else
do_find "$@"
fi