HackproofHacks
Penetration Testing 13 min read

Shell Scripting to Automate Reconnaissance: Build Your Own Recon Pipeline

Learn to automate the boring parts of recon with Bash, chaining subdomain enumeration, probing and content discovery into one repeatable script you actually own.

Hassan Ansari

Hassan Ansari

A terminal card showing a Bash recon pipeline chaining subdomain enumeration into httpx and nuclei

Shell Scripting to Automate Reconnaissance

Reconnaissance is where hacking is really won. Long before any exploit, the person who maps the target most thoroughly usually finds the way in. The trouble is that good recon is repetitive. The same commands, in the same order, against target after target. And repetition is exactly what computers are for.

So in this guide we are going to build your own reconnaissance pipeline with nothing more than Bash and a handful of free tools. Not a bloated framework you cannot see inside, but a script you own, understand, and can bend to any target in seconds. By the end you will have moved from typing the same commands by hand every time to running one script and going to make coffee while it works.

One line before we start, and I mean it every time. Everything here is for targets you own or are explicitly authorised to test, whether that is your own lab, a client engagement, or an asset inside a bug bounty program’s scope. Automation makes it trivially easy to scan things you should not, so scope carefully.

Why script it yourself

You might reasonably ask why bother writing your own scripts when polished all-in-one recon frameworks already exist. It is a fair question, and the honest answer is that both have their place. But building your own pipeline gives you three things the black boxes cannot.

The first is understanding. When you wire the tools together yourself, you learn exactly what each stage does and why it comes where it does. That knowledge pays off constantly, because when something behaves oddly on a real target you can reason about it instead of shrugging at a framework that failed silently.

The second is control. Your script, your rules. You decide which tools run, in what order, with what settings, and you can change any of it in seconds. When a target does something unusual, you adapt on the spot rather than fighting someone else’s assumptions.

The third is flexibility. Over time your script becomes yours, shaped by your habits and the kinds of targets you go after. It grows with you. That personal toolkit is one of the things that quietly separates hunters who plateau from those who keep getting sharper.

The building blocks of Bash you actually need

You do not need to be a shell wizard for this. Recon automation is mostly about gluing existing command-line tools together, and Bash is superb at exactly that. Here are the few pieces that do almost all the work.

Pipes are the single most important idea. The pipe symbol takes the output of one command and feeds it straight into the next. subfinder -d example.com | httpx sends every subdomain straight into a prober. Recon pipelines are, at heart, long chains of pipes.

Redirection means saving output to files with > and appending with >>. You will constantly want to capture results, subfinder -d example.com > subs.txt, so later stages can read them.

Variables store values so you do not repeat yourself. domain="example.com" lets you write the target once and reuse it everywhere, which is the first step toward a reusable script.

Loops do something to every line of a file. A simple while read loop lets you run a command against every host you discovered.

Arguments read input passed to your script with $1, so you can run ./recon.sh example.com and have it just work against whatever you point it at.

That really is the core. If those five ideas make sense to you, you can build everything below.

The shape of a recon pipeline

Before writing anything, picture the flow. Good recon moves in stages, each one feeding the next, gradually turning a single domain into a rich map of attack surface.

The typical pipeline looks like this. You start with a domain. You enumerate its subdomains to discover the wider footprint. You resolve and probe those subdomains to find which ones are actually alive and serving something. You gather historical and crawled URLs to uncover forgotten endpoints. Then you run content discovery and vulnerability templates against the live hosts to surface interesting paths and known issues. Each stage narrows and enriches the last.

Our job in scripting is simply to connect these stages so the output of one becomes the input of the next, automatically. Let us build it up piece by piece.

Stage one: subdomain enumeration

Everything begins with expanding one domain into all the hosts that belong to it. A tool like subfinder pulls subdomains from dozens of public sources quickly and passively. In a script it looks like this.

#!/bin/bash
domain="$1"
mkdir -p "$domain"
echo "[*] Enumerating subdomains for $domain"
subfinder -d "$domain" -silent > "$domain/subs.txt"
echo "[*] Found $(wc -l < "$domain/subs.txt") subdomains"

Look at what this small block already does. It takes the target as an argument, creates a folder to keep the results tidy, runs the enumeration silently, saves everything to a file, and tells you how many it found. That is a real, useful tool already, and we have barely started. If you want to go deeper on this stage specifically, the subdomain enumeration recon guide on this site covers the theory behind why these sources work.

Stage two: find what is actually alive

A list of subdomains is not much use on its own, because many will be dead, parked, or unreachable. The next stage probes each one to see which are actually responding, using a tool like httpx. We feed the previous stage straight in.

echo "[*] Probing for live hosts"
cat "$domain/subs.txt" | httpx -silent -o "$domain/live.txt"
echo "[*] $(wc -l < "$domain/live.txt") hosts are live"

Notice the cat ... | httpx pattern. We are piping the output of stage one directly into stage two. This is the whole philosophy of the pipeline in one line, the results flow forward on their own. Now live.txt holds only the hosts worth spending time on, which keeps every later stage faster and quieter.

Stage three: gather historical URLs

Live hosts often hide a wealth of old endpoints, forgotten parameters, and API paths that are not linked anywhere obvious. Tools like waybackurls and gau pull these from public archives and crawl data. We loop over our live hosts and collect everything.

echo "[*] Gathering historical URLs"
cat "$domain/live.txt" | waybackurls | sort -u > "$domain/urls.txt"
echo "[*] Collected $(wc -l < "$domain/urls.txt") URLs"

That sort -u at the end is a small but important habit. It sorts the results and strips duplicates, so you are not wading through the same URL a hundred times. Little touches like this are what make a homegrown script pleasant to actually use. There is a full write-up on this site about how attackers use waybackurls to find vulnerabilities if you want to understand what makes this stage so valuable.

Stage four: content discovery and templated checks

Now we hunt for hidden paths and known weaknesses. Content discovery with a tool like ffuf brute forces directories and files, while nuclei runs thousands of community templates that check for known misconfigurations and vulnerabilities against the live hosts.

echo "[*] Running nuclei against live hosts"
nuclei -l "$domain/live.txt" -silent -o "$domain/nuclei.txt"
echo "[*] Recon complete. Results saved in $domain/"

And that is a complete, end-to-end pipeline. One command in, a folder full of structured recon out. If content discovery is new to you, the guide to ffuf directory bruteforcing on this site walks through the tool that powers this stage in detail.

Bringing it together into one script

Here is the whole thing assembled into a single file. Save it as recon.sh, make it executable with chmod +x recon.sh, and run it with ./recon.sh example.com.

#!/bin/bash
# Simple recon pipeline. Authorised targets only.
domain="$1"

if [ -z "$domain" ]; then
  echo "Usage: ./recon.sh <domain>"
  exit 1
fi

mkdir -p "$domain"

echo "[*] Enumerating subdomains"
subfinder -d "$domain" -silent > "$domain/subs.txt"

echo "[*] Probing for live hosts"
cat "$domain/subs.txt" | httpx -silent -o "$domain/live.txt"

echo "[*] Gathering historical URLs"
cat "$domain/live.txt" | waybackurls | sort -u > "$domain/urls.txt"

echo "[*] Running templated checks"
nuclei -l "$domain/live.txt" -silent -o "$domain/nuclei.txt"

echo "[*] Done. Results in ./$domain/"

Notice the small guard near the top. If you forget to pass a domain, it tells you how to use it and stops rather than doing something confusing. That single check is the difference between a script that annoys you and one you actually trust. As you use this, you will keep adding these small quality-of-life touches, and that is exactly how a personal toolkit is born.

Making the script trustworthy: logging and error handling

The version above works, but a script you rely on needs to be a little more grown up. Two habits turn a fragile one-off into something you actually trust on real engagements.

The first is logging. When a run finishes and you find something interesting, you will want to know when it ran and how long each stage took. Adding timestamps costs almost nothing and pays off constantly. A simple helper function keeps it clean.

log() {
  echo "[$(date '+%H:%M:%S')] $1"
}

log "Enumerating subdomains"

Now every message in your pipeline is timestamped, so a log file becomes a record you can actually reason about later rather than an undated blur.

The second habit is not blindly charging ahead when a stage produces nothing. If subdomain enumeration returns an empty file, running every later stage against nothing just wastes time and clutters your output. A quick check prevents that.

if [ ! -s "$domain/subs.txt" ]; then
  log "No subdomains found, stopping."
  exit 1
fi

The -s test asks whether the file exists and is non-empty. Small guards like this are what separate a script that quietly does the wrong thing from one that tells you clearly what happened. As your pipeline grows, these checks between stages save you from chasing confusing results caused by an earlier step that silently failed.

Running it on a schedule

One of the real payoffs of scripting your recon is that a script can run without you. On engagements or bug bounty programs that last weeks, attack surface changes constantly. New subdomains appear, old services get exposed, and the person who notices first has the advantage. Rather than re-running your recon by hand every few days, you can schedule it.

On a Linux machine, cron is the classic tool for this. A single line in your crontab can run your pipeline automatically, say once a day, and because your script already saves organised, timestamped output per target, you build up a history over time. Compare today’s results against last week’s and the new entries jump out. That diffing of results over time, spotting what changed rather than re-reading everything, is one of the highest-value tricks in continuous recon, and it only becomes practical once your recon is a script rather than a manual ritual. You can even wire in a notification, a message to yourself when a run finds something new, so the pipeline effectively watches the target for you.

This is the moment the effort pays off. You stop performing recon and start operating a system that performs it for you, freeing your attention for the creative work that automation cannot do.

Making it yours, and using it responsibly

What you have now is a foundation, not a finished product, and that is the point. From here you will start customising. You might add screenshotting of live hosts so you can eyeball them quickly. You might pipe URLs through a parameter discovery tool before the vulnerability stage. You might add notifications so it pings you when a run finishes. Every one of those changes is a few lines, because the structure is already sound.

Two references will make the scripting half of this much less painful: ShellCheck catches the quoting and word-splitting bugs that silently corrupt pipelines like this one, and the Advanced Bash-Scripting Guide is a solid free reference when you need a construct you have not used before. The tools the pipeline drives (subfinder, httpx, nuclei, ffuf and waybackurls) are all worth reading the docs for rather than copying flags blindly.

A few habits will keep you out of trouble and make your results better. Be gentle with concurrency and speed, both to respect program rules and to avoid tripping defences that will feed you garbage data once they start blocking you. Keep your tools updated, since their data sources and templates improve constantly. And organise your output per target, as our script does with its folders, so a month from now you can still find what you gathered.

Above all, remember what makes this legitimate. The same automation that maps a target you are paid to test will happily map one you have no right to touch, and the tools do not know the difference. Scope carefully, stay inside your authorisation, and let the script do the boring work so your brain is free for the interesting part, which is turning all this reconnaissance into a way in.

#reconnaissance #bash #shell scripting #automation #bug bounty #recon #penetration testing
Free newsletter

Liked this? I write one like it every week.

One practical security lesson in your inbox each week, explained the same simple way. Join 10,000+ readers. Unsubscribe anytime.

From the article

Need a security assessment?

HackproofHacks provides web application and API penetration testing — using the same techniques covered in this article, with your explicit authorisation. See our penetration testing services.

More on Penetration Testing.

All articles →
FAQ

Questions about this topic.

Why automate reconnaissance with shell scripting instead of using an all-in-one tool?

Because writing your own scripts gives you control, understanding, and flexibility that a black-box tool cannot. You decide exactly which tools run, in what order, and how their output flows together, and you can tweak any step in seconds. Off-the-shelf frameworks are convenient, but building your own pipeline teaches you what each stage actually does and lets you adapt instantly when a target behaves unusually. Many top hunters use a mix of both.

Do I need to be good at Bash to automate recon?

You need surprisingly little to get started. If you can run commands, use pipes, save output to files, and write a simple loop, you already have enough to build a useful recon pipeline. The power of Bash for recon comes from chaining existing tools together rather than writing complex programs, so you grow your scripting as your needs grow rather than learning everything up front.

What tools should a recon pipeline chain together?

A common flow is subdomain enumeration with a tool like subfinder or amass, resolving and probing which hosts are alive with a tool like httpx or dnsx, gathering historical URLs with something like waybackurls or gau, and then running content discovery and vulnerability templates with tools such as ffuf and nuclei. The exact tools matter less than the pattern of passing the output of one stage cleanly into the next.

Is automated reconnaissance legal?

It is only legal against targets you own or are explicitly authorised to test, such as systems in a signed penetration testing engagement or assets that fall within a bug bounty program's scope. Automation makes it very easy to accidentally scan things outside your permission, so scoping carefully and respecting program rules is essential. The automation does not change the law, and unauthorised scanning can carry serious consequences.

How do I avoid getting my recon script blocked or rate limited?

Be considerate with speed and concurrency. Add delays, cap the number of parallel requests, and avoid hammering a single target with aggressive settings, both to stay within program rules and to avoid tripping defences. Respecting rate limits also produces cleaner, more reliable results, since a target that is busy blocking you is not giving you accurate data.

Should I use Bash or Python for recon automation?

Use Bash for gluing command-line tools together into pipelines, which is exactly what most recon is, and reach for Python when you need real logic, data parsing, or API work that Bash makes awkward. Many people start entirely in Bash because recon is mostly about orchestrating existing tools, then move individual pieces into Python as their needs get more complex. Neither is wrong, they suit different jobs.