How to Create a Bash File Conversion Tool

How to Create a Bash File Conversion Tool

How to Create a Bash File Conversion Tool

File conversion is one of those tasks that seems trivial until it happens fifty times a week — images that need resizing and reformatting, documents bouncing between markdown and PDF, CSVs that need to become JSON. Every individual conversion has a well-known command behind it, but remembering all of them, and typing them correctly each time, is where a wrapper script pays for itself immediately.

This article builds a Bash file conversion tool that detects input and target formats, dispatches to the right underlying utility, and handles the practical edge cases that come up in daily use.

Why a Unified Conversion Script?

Different file types need entirely different tools: convert/magick for images, pandoc for documents, ffmpeg for audio/video, jq for JSON transforms. A single entry point script:

Step 1: Detecting Source and Target Format

The simplest and most reliable approach is to infer format from file extensions on both sides:

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

INPUT="$1"
OUTPUT="$2"

[[ -f "$INPUT" ]] || { echo "Input file not found: $INPUT"; exit 1; }

SRC_EXT="${INPUT##*.}"
DST_EXT="${OUTPUT##*.}"

echo "Converting .$SRC_EXT -> .$DST_EXT"

"${INPUT##*.}" is Bash parameter expansion that strips everything up to and including the last dot, leaving just the extension. This is a fast, dependency-free way to identify format without invoking an external tool.

Step 2: Image Conversion

ImageMagick’s convert (or magick on newer versions) handles most image format conversions:

convert_image() {
    local src="$1" dst="$2"
    convert "$src" "$dst"
}

Example:

./convert-file.sh photo.png photo.jpg

Internally this runs convert photo.png photo.jpg, and ImageMagick auto-detects both formats from their headers, re-encoding accordingly. Quality and resizing options can be layered in:

convert "$src" -resize 50% -quality 85 "$dst"

Step 3: Document Conversion with Pandoc

Pandoc is the standard tool for converting between markup and document formats — markdown, HTML, DOCX, PDF, and more:

convert_document() {
    local src="$1" dst="$2"
    pandoc "$src" -o "$dst"
}
./convert-file.sh report.md report.pdf

Pandoc infers both formats from file extensions by default, but explicit format flags avoid ambiguity in less common cases:

pandoc -f markdown -t pdf "$src" -o "$dst"

Step 4: Audio/Video Conversion with FFmpeg

convert_media() {
    local src="$1" dst="$2"
    ffmpeg -i "$src" "$dst" -hide_banner -loglevel error -y
}
./convert-file.sh podcast.wav podcast.mp3

Step 5: Dispatching by Category

Putting it together with a category dispatcher based on extension:

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

INPUT="$1"
OUTPUT="$2"

[[ -f "$INPUT" ]] || { echo "Input file not found: $INPUT"; exit 1; }

SRC_EXT="${INPUT##*.}"
DST_EXT="${OUTPUT##*.}"

IMAGE_EXTS="png jpg jpeg gif bmp tiff webp"
DOC_EXTS="md markdown html docx pdf odt rtf"
MEDIA_EXTS="mp3 wav flac ogg mp4 mkv avi mov"

is_in() {
    local item="$1"; shift
    for x in "$@"; do [[ "$x" == "$item" ]] && return 0; done
    return 1
}

if is_in "$SRC_EXT" $IMAGE_EXTS && is_in "$DST_EXT" $IMAGE_EXTS; then
    convert "$INPUT" "$OUTPUT"
elif is_in "$SRC_EXT" $DOC_EXTS && is_in "$DST_EXT" $DOC_EXTS; then
    pandoc "$INPUT" -o "$OUTPUT"
elif is_in "$SRC_EXT" $MEDIA_EXTS && is_in "$DST_EXT" $MEDIA_EXTS; then
    ffmpeg -i "$INPUT" "$OUTPUT" -hide_banner -loglevel error -y
else
    echo "Error: unsupported or mismatched conversion: .$SRC_EXT -> .$DST_EXT"
    exit 1
fi

echo "Converted: $INPUT -> $OUTPUT"

The is_in helper function checks whether a value exists in a space-separated list, used here to classify both the source and destination extensions into the same category before picking a tool — this prevents nonsensical calls like trying to feed an image into ffmpeg.

Step 6: Adding CSV/JSON Data Conversion

Data format conversion deserves its own branch, since tools like jq and csvkit (or a quick Python one-liner) don’t overlap with the categories above:

elif [[ "$SRC_EXT" == "csv" && "$DST_EXT" == "json" ]]; then
    python3 -c "
import csv, json, sys
with open('$INPUT') as f:
    reader = csv.DictReader(f)
    data = list(reader)
with open('$OUTPUT', 'w') as f:
    json.dump(data, f, indent=2)
"
elif [[ "$SRC_EXT" == "json" && "$DST_EXT" == "csv" ]]; then
    python3 -c "
import csv, json
with open('$INPUT') as f:
    data = json.load(f)
if data:
    with open('$OUTPUT', 'w', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=data[0].keys())
        writer.writeheader()
        writer.writerows(data)
"

This uses python3 -c as a lightweight embedded scripting escape hatch — Bash itself has no native structured data handling, so leaning on Python for this specific pair is more reliable than attempting a pure awk/sed transformation, which gets fragile fast with quoted CSV fields.

Real-World Use Cases

Automation Example: Batch Convert a Directory

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

SRC_DIR="$1"
SRC_EXT="$2"
DST_EXT="$3"

for file in "$SRC_DIR"/*."$SRC_EXT"; do
    [[ -f "$file" ]] || continue
    OUT="${file%.*}.$DST_EXT"
    ./convert-file.sh "$file" "$OUT"
done

Usage: ./batch-convert.sh ./photos png webp converts every PNG in the folder to WebP, preserving the base filename.

Best Practices

Security Considerations

Optimization Tips

Troubleshooting

Common Mistakes

FAQs

Can this handle converting an entire batch with mixed formats? Yes, by looping over files and letting the extension-based dispatcher route each one to the correct tool individually.

Why use Pandoc instead of a direct DOCX-to-PDF library? Pandoc already handles a huge range of document format pairs consistently and is actively maintained, avoiding the need to individually wire up separate libraries for each format combination.

Is a GUI-free environment (server, container) suitable for this? Mostly yes — convert, ffmpeg, and pandoc are all fully usable headless; only some obscure format edge cases assume a display server, which is uncommon for the formats covered here.

Summary

A unified file conversion script turns a scattered set of tool-specific commands into one predictable interface. By classifying formats into categories (image, document, media, data) and dispatching to the right underlying tool — ImageMagick, Pandoc, FFmpeg, or a small Python snippet for structured data — the script scales cleanly from one-off conversions to full batch-processing pipelines.

References

Exit mobile version