Shell CGI Scripts
Shell CGI scripts: bash and sh for simple web tasks
Can you write a CGI script in bash or shell?
Yes, any executable the server can run can serve as a CGI script, including bash and sh scripts. A shell CGI script prints a Content-Type header and a blank line to stdout, then prints the response body. Reading form input requires manual URL decoding of QUERY_STRING for GET requests, which is fiddly and error-prone. Shell CGI is appropriate for very simple tasks, but for anything involving user input, Perl or Python is safer and easier to get right.
When shell CGI is appropriate
Shell CGI scripts are appropriate when the task does not involve user input at all, for example serving a dynamically generated server-status page that reads system statistics, or returning a JSON response built from the output of a known-safe system command. In these cases the simplicity of a short shell script is a genuine advantage over the overhead of loading a Perl or Python interpreter.
As soon as any user-supplied data (query string, form POST, HTTP headers) enters the script, the risk calculus changes sharply. Shell quoting rules are complex and easy to get wrong; command injection through untreated user input is extremely common in shell scripts. If you need to handle user input, use Perl or Python where taint mode, parameter parsing libraries, and explicit escaping functions make the job tractable.
Printing headers from a shell CGI script
A shell CGI script prints the Content-Type header to stdout with a double newline: printf 'Content-Type: text/html\n\n'. Using echo can work but varies between shells and OSes in how it handles newlines and the -e flag; printf is portable and predictable. The body follows immediately after.
Error messages from shell commands go to stderr, which the web server typically logs rather than sending to the browser, so you will not see command errors in the response unless you redirect them explicitly. During debugging, redirect stderr to stdout (2>&1) after the headers to see what went wrong, and remember to remove that redirect in production.
Reading GET parameters in a shell script
GET parameters arrive in the QUERY_STRING environment variable as a URL-encoded string like 'name=hello+world&age=30'. Decoding this in pure shell requires replacing + with space and decoding %XX sequences, which is error-prone without a library. A practical approach is to call a Python or Perl one-liner to do the decoding: VALUE=$(python3 -c "import urllib.parse,os; print(urllib.parse.parse_qs(os.environ.get('QUERY_STRING',''))['fieldname'][0])"). This is awkward enough to suggest that if you need more than one or two simple parameters, switching to a Python or Perl script is cleaner.
What to know
Key points
- Use printf, not echo, for reliable header output. printf 'Content-Type: text/html\n\n' is portable across shells and OSes.
- Avoid user input in shell CGI. Shell quoting and command injection are easy to get wrong; use Perl or Python for any script that processes form data.
- Shell CGI is reasonable for read-only status or static-ish content. Serving system stats or a pre-built JSON blob is a safe use of shell CGI.
Get help
Listings and a local agent, when you are ready
Need a CGI script built, debugged, or a hosting environment configured? Forms use a clearly-marked placeholder endpoint until wired to a real system.
Reserved for an affiliate link to a vetted shared or VPS hosting provider that supports CGI and Perl/Python execution. Operator wires affiliate link here.
Self-hosted lead form for custom CGI development inquiries. Placeholder endpoint until wired to the operator's CRM or email handler.
Open inquiry form →Custom CGI development
Hosting setup help
Questions