Converting one file is a click. Converting a thousand files is an engineering problem. You have a photo archive of 5,000 RAW images that need JPEG versions for web delivery. Or a folder of 200 DOCX reports to convert to PDF for archival. Or a video library of 300 AVI files to transcode to MP4. Doing this one file at a time would take days.
Batch conversion is the solution, and it's built on four command-line powerhouses: FFmpeg (audio/video), ImageMagick (images), LibreOffice (documents), and Pandoc (markup/text). Each can be scripted to process an entire directory tree, handle errors, log results, and produce consistent output. This guide covers the practical scripts and strategies for each tool.
FFmpeg: Audio and Video Batch Processing
FFmpeg processes virtually any audio or video format. It's the engine behind ChangeThisFile's server-side audio and video conversions.
Common Batch Scripts
Convert all AVI to MP4 (H.264):
for f in *.avi; do
ffmpeg -i "$f" -c:v libx264 -crf 23 -c:a aac -b:a 128k "${f%.avi}.mp4"
doneConvert all FLAC to MP3 (320kbps):
for f in *.flac; do
ffmpeg -i "$f" -c:a libmp3lame -b:a 320k "${f%.flac}.mp3"
doneExtract audio from all video files:
for f in *.mp4; do
ffmpeg -i "$f" -vn -c:a copy "${f%.mp4}.m4a"
doneConvert all MKV to MP4 (stream copy, no re-encoding):
for f in *.mkv; do
ffmpeg -i "$f" -c copy "${f%.mkv}.mp4"
doneStream copy (-c copy) is dramatically faster than re-encoding because it simply repackages the existing streams. Use it whenever you're changing container but not codec. MKV to MP4 and MOV to MP4 often work with stream copy.
FFmpeg Batch Tips
- Overwrite control: Add
-nto skip existing outputs, or-yto overwrite. Default behavior is to ask, which hangs batch scripts. - Error handling: Check exit code with
$?. FFmpeg returns 0 on success, non-zero on failure. - Recursive processing: Use
find . -name '*.avi' -exec ffmpeg ...orfind . -name '*.avi' | while read f; do ... donefor subdirectories. - Metadata preservation: FFmpeg copies metadata by default. Add
-map_metadata 0explicitly if metadata is disappearing, or-map_metadata -1to strip it.
ImageMagick: Image Batch Processing
ImageMagick's mogrify command is designed specifically for batch operations — it converts files in place (or to a new directory).
Common Batch Scripts
Convert all PNG to JPG (quality 85):
mogrify -format jpg -quality 85 *.pngConvert all images to WebP, save in a different directory:
mkdir -p webp_output
mogrify -format webp -path webp_output *.{jpg,png,bmp}Resize all images to max 1920px wide:
mogrify -resize 1920x\> *.jpgThe \> flag means "only resize if larger" — images under 1920px are left untouched.
Convert and resize in one pass:
mogrify -format webp -resize 1200x -quality 80 -path output/ *.pngFor higher performance, consider using sharp (Node.js/libvips) or vips directly — they're 5-10x faster than ImageMagick for bulk operations. PNG to WebP and JPG to WebP conversions are especially fast with libvips.
LibreOffice Headless: Document Batch Processing
LibreOffice's headless mode converts documents without a GUI, making it ideal for server-side and batch operations.
Convert all DOCX to PDF:
libreoffice --headless --convert-to pdf --outdir output/ *.docxConvert all XLSX to CSV:
libreoffice --headless --convert-to csv --outdir output/ *.xlsxConvert all PPT to PPTX:
libreoffice --headless --convert-to pptx --outdir output/ *.ppt
LibreOffice Batch Limitations
Single-instance bottleneck: LibreOffice headless runs one conversion at a time. A second instance attempting to start will either queue or fail. For large batches, this means conversions are sequential — 1,000 DOCX files at 3 seconds each means 50 minutes. Don't try to parallelize with xargs -P or GNU Parallel — it will cause lock conflicts.
Font dependency: Output quality depends on installed fonts. If the DOCX uses Calibri and your system doesn't have it, LibreOffice substitutes, causing layout shifts. Install Microsoft core fonts before batch converting: apt install ttf-mscorefonts-installer on Ubuntu.
ChangeThisFile uses LibreOffice headless for server-side document conversions: DOCX to PDF, XLSX to CSV, PPTX to PDF, and more.
Pandoc: Markup and Text Batch Processing
Pandoc converts between markup formats: Markdown, HTML, LaTeX, reStructuredText, DOCX, EPUB, and more.
Convert all Markdown to HTML:
for f in *.md; do
pandoc "$f" -o "${f%.md}.html" --standalone
doneConvert all Markdown to PDF (via LaTeX):
for f in *.md; do
pandoc "$f" -o "${f%.md}.pdf" --pdf-engine=xelatex
doneConvert all HTML to DOCX:
for f in *.html; do
pandoc "$f" -o "${f%.html}.docx"
donePandoc is fast — it processes text-based formats in milliseconds per file. A batch of 1,000 Markdown files converts to HTML in under a minute. Related: Markdown to HTML, HTML to Markdown, Markdown to PDF.
Parallel Processing with GNU Parallel
For CPU-bound conversions (FFmpeg encoding, ImageMagick processing), parallel execution dramatically reduces total time. GNU Parallel distributes work across CPU cores:
Convert AVI to MP4 using all CPU cores:
find . -name '*.avi' | parallel -j$(nproc) \
ffmpeg -i {} -c:v libx264 -crf 23 -c:a aac {.}.mp4Convert PNG to WebP with 4 parallel workers:
find . -name '*.png' | parallel -j4 \
convert {} -quality 80 {.}.webpHow many parallel jobs? For FFmpeg video encoding, 2-4 parallel jobs (each FFmpeg process uses multiple threads internally). For ImageMagick image conversion, match the number of CPU cores. For LibreOffice, only 1 (single-instance limitation). For Pandoc, match CPU cores (it's single-threaded per invocation).
Error Handling and Logging
Batch conversion without error handling means you discover 50 failed files after the entire batch finishes — and you don't know which ones. Always log results:
#!/bin/bash
LOG="conversion_$(date +%Y%m%d_%H%M%S).log"
FAILED=0
SUCCESS=0
for f in *.avi; do
echo "Converting: $f" | tee -a "$LOG"
if ffmpeg -y -i "$f" -c:v libx264 -crf 23 -c:a aac "${f%.avi}.mp4" 2>>"$LOG"; then
echo " SUCCESS" | tee -a "$LOG"
((SUCCESS++))
else
echo " FAILED" | tee -a "$LOG"
((FAILED++))
fi
done
echo "\nComplete: $SUCCESS succeeded, $FAILED failed" | tee -a "$LOG"Key practices:
- Log everything. Redirect stderr to a log file. FFmpeg's error messages explain exactly why a conversion failed.
- Count successes and failures. A summary at the end tells you immediately if something went wrong.
- Don't stop on first error. Use conditional execution (if/then) rather than
set -e. One corrupted file shouldn't abort the remaining 999. - Verify outputs. After batch conversion, check that output file count matches input, and spot-check a few files for quality.
Naming Conventions and Directory Structure
Three strategies for batch output organization:
- Same directory, new extension:
photo.png→photo.webp. Simplest, but mixes originals and conversions. - Output subdirectory:
originals/photo.png→converted/photo.webp. Clean separation. Use-path(mogrify) or-outdir(LibreOffice). - Suffix-based:
photo.png→photo_web.webp. Keeps files together while distinguishing originals from derivatives.
The cardinal rule: never overwrite originals. Keep source files untouched until you've verified all conversions succeeded. An interrupted batch that overwrites files in place leaves you with neither the original nor the complete conversion.
Batch conversion is where command-line tools pay for themselves. A 10-line Bash script replacing 5,000 manual clicks isn't premature optimization — it's basic sanity. The investment in learning FFmpeg, ImageMagick, or LibreOffice headless syntax pays dividends every time you face a folder full of files in the wrong format.
For one-off conversions, use ChangeThisFile's web converter. For bulk operations, take the scripts in this guide, adapt them to your file types, and let the machine do the repetitive work. That's what computers are for.