Text
To Find by Content
You’re usually looking for something in a file. Some phrase or word, and you don’t know where the file is at or what you named it.
For occasional search through file content at the command line you’d use grep. Something like:
grep --ignore-case --files-with-matches --recursive foo /some/file/path
This can take quite a while. There are some tweaks to grep you can add, but for source code it’s become fashionable to use use ripgrep or ugrep.
sudo apt install ugrep
# a drop-in for grep in most cases
ug --ignore-case --files-with-matches --recursive foo /some/file/path
You can also use ugrep interactively with the -Q option. Though you may prefer a whiptail style menu - see the bottom.
To Find by File Name
If you know the name of the file you want, it’s usually a matter of using the find utility or locate.
find /some/place -iname "*something*"
On large filesystems, the locate utility is much faster, as it pre-builds a database.
# 'plocate' is the modern replacement for the locate utility
sudo apt install plocate
# a systemd timer updates this database daily, but to use immediately after install you must:
sudo updatedb
sudo locate -i "*something*"
You can also use a utility like fzf which uses some fuzzy name matching and includes shell integration. This has become more popular recently.
How to Build a Menu Around This
This isn’t about search per se, but this is a great place to mention whiptail, a text user interface. This let’s you wrap a TUI around your search regardless what tool you use.
sudo apt instal whiptail
# We'll name our search utility 'f'
vi ~/bin/f
#!/bin/bash
[ -z "$1" ] && { echo "You must supply a search term."; exit; }
# Pipe the output of the search to a while loop that will build two arrays; One is a list
# of files and the other a list of those file's basenames we can use for a pretty menu.
# We'll add numbers to the menu array so that when the user chooses a basename, we will
# know what filename to pull from the other array.
FILENUMBER=0
FILENAME=
LIST=()
MENU=()
LOCATION=/home/allen/projects
ug --ignore-case --files-with-matches --recursive "$1" $LOCATION | \
{
while read FILENAME; do
LIST=( "${LIST[@]}" "$FILENAME" )
DATE=$(stat -c '%.10y' "$FILENAME")
BASENAME=$(basename "$FILENAME")
MENU=( "${MENU[@]}" "$FILENUMBER" "$DATE $BASENAME" )
((FILENUMBER++))
done
# If there are no results
[ -z "${LIST[0]}" ] && { echo "No results"; exit; }
# Return the filenumber from the user's choice so we can access that array element
while [ 1 ]; do
KEY=$( whiptail --title "Search Results" --notags --menu "Search Results" 25 78 16 "${MENU[@]}" 3>&1 1>&2 2>&3 )
[ -z $KEY ] && exit
less "${LIST[$KEY]}"
done
} # The braces are required so that the while loops can modify 'global' variables
Notes
Why don’t we index the file contents?
You’d think an index would be great - but it turns out for unstructured text files you’re indexing every word in every file, making the index is larger than the things it’s indexing.
Though lucene/elasticseach and spinx come up in conversation.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.