Skip to content

Instantly share code, notes, and snippets.

@akkartik
Created September 7, 2023 23:06
Show Gist options
  • Save akkartik/8ada765dbf7a04613bd04523be5332d2 to your computer and use it in GitHub Desktop.
Save akkartik/8ada765dbf7a04613bd04523be5332d2 to your computer and use it in GitHub Desktop.
search -- from the outside in and from the inside out
#!/usr/bin/zsh
# Search a directory for files containing all of the given keywords.
# Credit: Kragen Sitaker for the idea of tail recursion using `exec $0`
ROOT=${ROOT:-.}
# Use absence of "--" to signal the outermost call.
# Recursive calls of $0 inside this script will always start with "--"
if [[ $1 != "--" ]]
then
# recursive calls exchange information using null-terminated lines
# get rid of nulls in the outermost call
# also sort for consistency
ROOT="$ROOT" exec $0 -- $* |xargs -n 1 -0 echo |sort
exit $? # TODO: Why is this needed?!
fi
# Only internal calls starting with "--" get to this point.
shift # skip the --
if [[ $# -eq 0 ]]
then
# base case: generate a list of files on stdout
exec find "$ROOT" -type f -print0
else
# search through the files coming in on stdout for one term, then recurse
keyword=$1
shift
if echo $keyword |grep -q '[A-Z]'
then
ROOT="$ROOT" exec $0 -- $* | xargs -0 grep -lZ "$keyword"
else
ROOT="$ROOT" exec $0 -- $* | xargs -0 grep -ilZ "$keyword"
fi
fi
@akkartik
Copy link
Author

akkartik commented Sep 7, 2023

Simpler version showing the bug, without ROOT or case-insensitive search.

#!/usr/bin/zsh
# Search a directory for files containing all of the given keywords.

# Credit: Kragen Sitaker for the idea of tail recursion using `exec $0`

# Use absence of "--" to signal the outermost call.
# Recursive calls of $0 inside this script will always start with "--"
if [[ $1 != "--" ]]
then
  # recursive calls exchange information using null-terminated lines to handle spaces in filenames
  # get rid of nulls in the outermost call
  # also sort for consistency
  exec $0 -- $* |xargs -n 1 -0 echo  |sort
  res=$?
  echo zzz
  exit $res
fi

# Only internal calls starting with "--" get to this point.
shift  # skip the --

if [[ $# -eq 0 ]]
then
  # base case: generate a list of files on stdout
  exec find . -type f -print0
else
  # search through the files coming in on stdout for one term, then recurse
  keyword=$1
  shift
  exec $0 -- $* | xargs -0 grep -lZ "$keyword"
fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment