How to Create a Bash File Search Tool

How to Create a Bash File Search Tool

How to Create a Bash File Search Tool

If you’ve ever spent ten minutes clicking through folders trying to find a single file, you already know why I decided to build my own file search tool in Bash. Linux gives you find and locate out of the box, but neither of them is exactly friendly when you’re in a hurry or when you want a repeatable, opinionated way of searching across your entire system. So I built a small, focused search tool as a Bash script, and in this article I’m walking you through exactly how I did it — from the absolute basics to the more advanced tricks that make the script genuinely useful in daily work.

By the end of this guide you’ll understand not just how to copy-paste a script, but how every line of it actually works.

Why Build a Custom Search Tool When find Already Exists?

That’s a fair question. find is powerful, but it’s also verbose. I got tired of typing:

find /home/user -iname "*invoice*" -type f -mtime -30

every single time I needed to search for something. I wanted a tool where I could just type:

fsearch invoice

and get sensible results immediately, with color-coded output, file size, and last-modified date. That’s the itch this project scratches.

Prerequisites

Before we start, make sure you have:

Step 1: Planning the Script’s Behavior

Before writing code, I always sketch out what I want the tool to do. For this search tool, my requirements were:

  1. Search by filename (partial match, case-insensitive)
  2. Optionally restrict the search to a specific directory
  3. Optionally filter by file extension
  4. Show file size and last modified date in the output
  5. Handle the “no results found” case gracefully

Step 2: Writing the Basic Script

Let’s start simple and build up from there. Create a new file:

touch fsearch.sh
chmod +x fsearch.sh

Now open it in your editor of choice and add this:

#!/usr/bin/env bash

# fsearch.sh - a simple file search tool

set -euo pipefail

QUERY="$1"
SEARCH_DIR="${2:-.}"

find "$SEARCH_DIR" -iname "*${QUERY}*" -type f 2>/dev/null

Run it like this:

./fsearch.sh report ~/Documents

Breaking Down Every Line

Step 3: Adding Better Output Formatting

Raw file paths are fine, but I wanted more context. Let’s enhance it:

#!/usr/bin/env bash
set -euo pipefail

QUERY="${1:-}"
SEARCH_DIR="${2:-.}"

if [[ -z "$QUERY" ]]; then
    echo "Usage: $0 <search-term> [directory]"
    exit 1
fi

echo "Searching for '$QUERY' in '$SEARCH_DIR'..."
echo "----------------------------------------"

RESULTS=$(find "$SEARCH_DIR" -iname "*${QUERY}*" -type f 2>/dev/null)

if [[ -z "$RESULTS" ]]; then
    echo "No files found matching '$QUERY'."
    exit 0
fi

while IFS= read -r file; do
    size=$(stat -c "%s" "$file" 2>/dev/null || stat -f "%z" "$file" 2>/dev/null)
    modified=$(stat -c "%y" "$file" 2>/dev/null || stat -f "%Sm" "$file" 2>/dev/null)
    printf "%-50s %10s bytes   %s\n" "$file" "$size" "$modified"
done <<< "$RESULTS"

What’s New Here

Step 4: Adding Extension Filtering

Sometimes you only want .pdf files or .log files. Let’s add that as an optional third argument:

EXTENSION="${3:-}"

if [[ -n "$EXTENSION" ]]; then
    RESULTS=$(find "$SEARCH_DIR" -iname "*${QUERY}*.${EXTENSION}" -type f 2>/dev/null)
else
    RESULTS=$(find "$SEARCH_DIR" -iname "*${QUERY}*" -type f 2>/dev/null)
fi

Now you can run:

./fsearch.sh invoice ~/Documents pdf

and it will only return PDF files whose names contain “invoice.”

Step 5: Making It a Global Command

Copy-pasting a script path every time gets old. I like to drop useful scripts into /usr/local/bin so they’re available system-wide:

sudo cp fsearch.sh /usr/local/bin/fsearch
sudo chmod +x /usr/local/bin/fsearch

Now you can just type fsearch invoice from anywhere in your terminal.

Real-World Use Cases

I use this tool constantly for a few specific scenarios:

Automating the Search Tool

You can wire this into cron for scheduled reports. For example, to email yourself a daily list of new PDFs added to a shared folder:

0 8 * * * /usr/local/bin/fsearch "" /shared/folder pdf | mail -s "Daily PDF Report" you@example.com

This runs the search every morning at 8 AM and mails you the results.

Security Considerations

A few things I always keep in mind when writing search scripts like this:

Optimization Tips

find "$SEARCH_DIR" -maxdepth 3 -iname "*${QUERY}*"
find "$SEARCH_DIR" -path "*/node_modules" -prune -o -iname "*${QUERY}*" -print

Troubleshooting Common Issues

Common Mistakes to Avoid

Frequently Asked Questions

Can this script search file contents, not just filenames? Not in its current form — it only searches names. To search file contents, combine it with grep -r "$QUERY" "$SEARCH_DIR".

Does this work on macOS? Yes, with the caveat that stat syntax differs slightly between GNU (Linux) and BSD (macOS) — I’ve accounted for that with the fallback logic shown above.

How do I make the search recursive only one level deep? Add -maxdepth 1 to the find command.

Can I search multiple directories at once? Yes — find accepts multiple paths: find dir1 dir2 dir3 -iname "*query*".

Summary

Building your own Bash file search tool isn’t about reinventing find — it’s about wrapping it in exactly the interface and defaults you want. We started with a one-line script and built it up into something with input validation, formatted output, extension filtering, and real error handling. Along the way we covered the reasoning behind set -euo pipefail, safe variable quoting, and cross-platform stat handling — all fundamentals that will serve you well in any Bash project going forward.

References

Exit mobile version