I needed a fast way to generate QR codes for a stack of Wi-Fi passwords and product links I was printing onto labels for a small event I helped organize. Opening a browser-based QR generator for each one would’ve been painfully slow, so I put together a small Bash script around qrencode, and it turned a half-hour chore into a batch job that finished in seconds. Here’s exactly how I built it.
Why Generate QR Codes from Bash
QR code generation seems like a “GUI tool” kind of task, but doing it from the command line has real advantages:
- You can batch-generate hundreds of QR codes from a list (URLs, contact cards, Wi-Fi credentials) in one pass.
- It integrates cleanly into automated pipelines — generating a QR code the moment a new record is added to a database or spreadsheet.
- No need to trust a third-party website with potentially sensitive data (like Wi-Fi passwords or personal contact info) that a browser-based generator would otherwise process on a remote server.
The Tool Behind It: qrencode
The most widely used command-line QR code generator is qrencode, part of the libqrencode project.
Install on Debian/Ubuntu:
sudo apt update
sudo apt install qrencode
On Fedora:
sudo dnf install qrencode
On macOS (via Homebrew):
brew install qrencode
The Simplest QR Code Generator
qrencode -o qrcode.png "https://example.com"
This generates a PNG file named qrcode.png encoding the given URL. That’s the entire core operation — everything else is about making it flexible and reusable.
Displaying a QR Code Directly in the Terminal
For a quick preview without opening an image viewer, qrencode can render directly as ASCII art:
qrencode -t ANSIUTF8 "https://example.com"
This is genuinely useful when SSH’d into a remote server and you want to scan something (like a two-factor auth secret) without transferring a file.
A Basic Bash Script Wrapper
#!/bin/bash
set -euo pipefail
usage() {
echo "Usage: $0 <text_or_url> <output_file.png>"
exit 1
}
if [ "$#" -ne 2 ]; then
usage
fi
content="$1"
output_file="$2"
qrencode -o "$output_file" -s 10 -l H "$content"
echo "QR code saved to $output_file"
How This Works Internally
-o "$output_file"specifies the output image path.-s 10sets the size of each QR “module” (pixel block) to 10 pixels, controlling overall image resolution.-l Hsets the error correction level to “High,” meaning the QR code can still be scanned even if up to 30% of it is damaged or obscured — useful for printed labels that might get smudged or scratched.
Batch-Generating QR Codes from a List
Here’s a script that reads a list of items from a text file (one per line) and generates a QR code for each:
#!/bin/bash
set -euo pipefail
input_list="$1"
output_dir="qrcodes"
mkdir -p "$output_dir"
counter=1
while IFS= read -r line; do
[ -z "$line" ] && continue
filename=$(printf "%s/qr_%03d.png" "$output_dir" "$counter")
qrencode -o "$filename" -s 8 -l H "$line"
echo "Generated: $filename for '$line'"
((counter++))
done < "$input_list"
echo "All QR codes generated in '$output_dir/'"
Breaking It Down
while IFS= read -r linereads the input file line by line, preserving whitespace and preventing backslash escaping issues.[ -z "$line" ] && continueskips blank lines in the input file.printf "%s/qr_%03d.png"builds a zero-padded, sequential output filename for each generated code.
Generating QR Codes from a CSV File (Name + URL Pairs)
A more structured, real-world version reads name/value pairs from a CSV and names each output file after the record:
#!/bin/bash
set -euo pipefail
csv_file="$1"
output_dir="qrcodes"
mkdir -p "$output_dir"
while IFS=',' read -r name url; do
[ -z "$name" ] && continue
safe_name=$(echo "$name" | tr ' ' '_' | tr -cd 'A-Za-z0-9_-')
qrencode -o "$output_dir/${safe_name}.png" -s 8 -l H "$url"
echo "Generated QR for $name -> $output_dir/${safe_name}.png"
done < "$csv_file"
Given a CSV like:
Product A,https://example.com/product-a
Product B,https://example.com/product-b
This produces Product_A.png and Product_B.png, each encoding the corresponding URL.
Generating a Wi-Fi QR Code
QR codes can also encode structured Wi-Fi connection data, so scanning the code automatically connects a phone to a network:
#!/bin/bash
ssid="MyNetwork"
password="SuperSecret123"
encryption="WPA" # WPA, WEP, or nopass
qrencode -o wifi_qr.png -s 10 -l H "WIFI:T:${encryption};S:${ssid};P:${password};;"
The format WIFI:T:<type>;S:<ssid>;P:<password>;; is a standard recognized by most modern phone camera apps, letting a scan connect instantly without manually typing the password.
Real-World Use Cases
- Event badges and labels: Generating unique QR codes for attendee check-in or product labeling.
- Wi-Fi sharing: Printing scannable Wi-Fi QR codes for guests instead of sharing passwords verbally.
- Inventory management: Encoding product IDs or SKUs into QR codes for warehouse scanning systems.
- Two-factor authentication setup: Displaying TOTP secret URIs as terminal QR codes when setting up authenticator apps on remote servers.
- Marketing materials: Bulk-generating QR codes linking to different landing pages for a print campaign.
Automation Example
Here’s a script I use that watches a folder for new CSV exports (e.g., from a spreadsheet tool) and automatically regenerates QR codes whenever the file changes:
#!/bin/bash
set -euo pipefail
csv_file="/data/product_links.csv"
output_dir="/data/qrcodes"
last_hash_file="/tmp/qr_csv_hash"
mkdir -p "$output_dir"
current_hash=$(sha256sum "$csv_file" | awk '{print $1}')
last_hash=$(cat "$last_hash_file" 2>/dev/null || echo "")
if [ "$current_hash" != "$last_hash" ]; then
while IFS=',' read -r name url; do
[ -z "$name" ] && continue
safe_name=$(echo "$name" | tr ' ' '_' | tr -cd 'A-Za-z0-9_-')
qrencode -o "$output_dir/${safe_name}.png" -s 8 -l H "$url"
done < "$csv_file"
echo "$current_hash" > "$last_hash_file"
echo "QR codes regenerated due to CSV changes."
else
echo "No changes detected in CSV; skipping regeneration."
fi
This only regenerates QR codes when the source CSV file has actually changed, avoiding unnecessary reprocessing on every cron run.
Best Practices
- Use error correction level
Hfor anything that will be printed physically, since printed materials are prone to smudging, folding, or partial obstruction. - Sanitize filenames derived from user data (like product names) before using them as output paths.
- Keep QR code content short where possible — shorter strings produce simpler, more reliably scannable codes.
- Test generated QR codes with multiple scanner apps before mass-printing, since rendering size and contrast can affect scan reliability.
- Store a manifest (CSV or log) mapping each generated QR code back to its original content for future reference.
Security Considerations
- Sensitive data exposure: QR codes encoding Wi-Fi passwords or personal data should be treated as sensitive artifacts — store and distribute them as carefully as you would the plaintext credentials themselves.
- Malicious QR content: Never programmatically generate QR codes from unsanitized, untrusted user input without validating that the content isn’t being used to smuggle malicious links into your own materials.
- Third-party generators: Avoid pasting sensitive information (like Wi-Fi passwords) into random third-party web-based QR generators — this is precisely why generating locally with
qrencodeis a safer default. - File permissions: If generated QR codes encode sensitive information, restrict read permissions on the output directory appropriately.
Optimization Tips
- Batch-generate QR codes in parallel using
xargs -Pwhen processing very large lists:
cat urls.txt | xargs -P 4 -I{} qrencode -o "qr_{}.png" "{}"
(Note: this simplified example needs adjustment for filenames with special characters — sanitize before using in production.)
- Use PNG for print-quality output and SVG (
-t SVG) for scalable vector graphics if the QR code needs to be resized without quality loss. - Lower
-s(module size) for on-screen or digital-only QR codes where extreme print resolution isn’t necessary, reducing file size.
Troubleshooting Common Issues
Problem: qrencode: command not found. Install it via your package manager and confirm with qrencode --version.
Problem: Generated QR code won’t scan. Increase the error correction level (-l H) and module size (-s), and ensure there’s adequate white space (“quiet zone”) around the code when printed.
Problem: Wi-Fi QR code doesn’t connect automatically. Double-check the exact format string — a missing semicolon or incorrect encryption type (WPA vs WEP vs nopass) will break parsing on the scanning device.
Problem: Special characters in content break the QR encoding. Ensure the string is properly quoted when passed to qrencode, and check the encoding of your input file (UTF-8 is recommended).
Common Mistakes to Avoid
- Using low error correction levels for printed materials that are likely to get damaged or dirty.
- Not sanitizing filenames generated from arbitrary text data, risking invalid or colliding filenames.
- Encoding sensitive data (like Wi-Fi passwords) without considering where the resulting image file will be stored or shared.
- Assuming every scanner app supports every QR code type (like Wi-Fi or vCard) equally well — test across multiple devices.
Frequently Asked Questions
Can qrencode generate QR codes for contact cards (vCard)? Yes, format the content as a standard vCard string (BEGIN:VCARD...END:VCARD) and pass it as the content argument, and most scanner apps will recognize it as a contact card.
What’s the maximum amount of data a QR code can hold? Up to about 4,296 alphanumeric characters, though practical scanability drops significantly as content length grows — shorter is generally better.
Can I generate colored QR codes? qrencode itself only generates black-and-white codes; for colored or styled QR codes, you’d need to post-process the output with an image tool like ImageMagick.
Is it possible to generate QR codes without installing anything? Not without a dependency — qrencode (or an equivalent library) is required since QR generation involves nontrivial encoding logic that Bash itself doesn’t provide natively.
Can I embed a logo in the middle of a generated QR code? Not directly through qrencode; you’d generate the QR code with high error correction (-l H) and then overlay a logo image using ImageMagick, since higher error correction tolerates the added obstruction.
Summary
Generating QR codes in Bash is a great example of Bash’s strength as an orchestration layer — the actual encoding logic lives in qrencode, while Bash handles batching, file naming, input parsing, and automation. Starting from a single qrencode -o file.png "text" command, you can build a tool that processes entire CSV files, generates Wi-Fi credentials, and integrates into automated content pipelines, all without ever touching a browser-based generator or exposing sensitive data to a third party.
References
libqrencodeproject page: https://fukuchi.org/works/qrencode/- QR Code specification overview (ISO/IEC 18004): https://www.iso.org/standard/62021.html
- Bash Reference Manual: https://www.gnu.org/software/bash/manual/bash.html
- GNU Coreutils
sha256sumdocumentation: https://www.gnu.org/software/coreutils/manual/html_node/sha2-utilities.html
