How to Generate QR Codes in Bash

How to Generate QR Codes in Bash

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 10 sets the size of each QR “module” (pixel block) to 10 pixels, controlling overall image resolution.
  • -l H sets 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 line reads the input file line by line, preserving whitespace and preventing backslash escaping issues.
  • [ -z "$line" ] && continue skips 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 H for 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 qrencode is 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 -P when 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

  • libqrencode project 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 sha256sum documentation: https://www.gnu.org/software/coreutils/manual/html_node/sha2-utilities.html
Total
2
Shares

Leave a Reply

Previous Post
How to Create a Bash URL Shortener

How to Create a Bash URL Shortener

Next Post
How to Create a Bash Image Resizer

How to Create a Bash Image Resizer

Related Posts