I once had a folder of a few hundred product photos, all at wildly inconsistent resolutions, that needed to be resized to a uniform dimension before uploading to an online store. Opening each one in an image editor would have taken hours. Instead, I wrote a small Bash script around ImageMagick, and what used to be an afternoon of tedious clicking became a five-second command. Here’s the full breakdown of how I built it.
Why Use Bash for Image Resizing
Bash itself doesn’t manipulate image data — that job belongs to dedicated image-processing libraries. But Bash is the perfect orchestration layer for:
- Batch-processing hundreds or thousands of images with a single command.
- Wiring image resizing into automated pipelines (upload processing, thumbnail generation, backups).
- Combining resizing with renaming, format conversion, and compression in one pass.
The Tool Behind It: ImageMagick
The most common and powerful tool for this job is ImageMagick, specifically its convert (or newer magick) command.
Install it on Debian/Ubuntu:
sudo apt update
sudo apt install imagemagick
On Fedora:
sudo dnf install ImageMagick
On macOS (via Homebrew):
brew install imagemagick
The Simplest Resize Command
convert input.jpg -resize 800x600 output.jpg
This resizes input.jpg so it fits within an 800×600 bounding box while preserving the original aspect ratio (ImageMagick won’t distort the image unless you explicitly force exact dimensions).
A Basic Batch Resizer Script
#!/bin/bash
set -euo pipefail
target_size="800x600"
output_dir="resized"
mkdir -p "$output_dir"
for img in *.jpg *.png; do
[ -e "$img" ] || continue
convert "$img" -resize "$target_size" "$output_dir/$img"
echo "Resized: $img"
done
echo "All images resized into '$output_dir/'"
How This Works Internally
mkdir -p "$output_dir"creates the output folder if it doesn’t already exist, without erroring if it does.- The
for img in *.jpg *.pngloop expands both glob patterns, catching common image formats. convert "$img" -resize "$target_size" "$output_dir/$img"resizes each matched image and writes the result into the output directory using the same filename.[ -e "$img" ] || continueguards against a glob pattern matching nothing (e.g., no.pngfiles present).
Forcing Exact Dimensions (Ignoring Aspect Ratio)
Sometimes you need an exact width and height regardless of distortion, such as for a fixed-size thumbnail grid:
convert input.jpg -resize 300x300! output.jpg
The ! after the dimensions tells ImageMagick to ignore the original aspect ratio and force the exact size specified.
Resizing by Percentage
convert input.jpg -resize 50% output.jpg
This scales the image down to 50% of its original dimensions — useful when you want proportional resizing without specifying exact pixel values.
A More Advanced Script with Aspect Ratio Preservation and Quality Control
#!/bin/bash
set -euo pipefail
usage() {
echo "Usage: $0 <width>x<height> <quality 1-100> <input_dir> <output_dir>"
exit 1
}
if [ "$#" -ne 4 ]; then
usage
fi
dimensions="$1"
quality="$2"
input_dir="$3"
output_dir="$4"
mkdir -p "$output_dir"
find "$input_dir" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" \) -print0 |
while IFS= read -r -d '' img; do
filename=$(basename "$img")
convert "$img" -resize "$dimensions" -quality "$quality" "$output_dir/$filename"
echo "Processed: $filename"
done
echo "Batch resize complete."
Breaking Down the Key Parts
find ... -print0combined withwhile IFS= read -r -d ''safely handles filenames containing spaces or special characters, unlike plain glob loops.-inamemakes the pattern match case-insensitively, catching both.jpgand.JPG.-quality "$quality"controls JPEG compression quality (1–100), letting you balance file size against visual fidelity.basename "$img"strips the directory path, leaving just the filename for constructing the output path.
Generating Thumbnails Alongside Full-Size Images
A common real-world pattern is generating both a resized “display” version and a small thumbnail:
#!/bin/bash
set -euo pipefail
input_dir="$1"
display_dir="display"
thumb_dir="thumbnails"
mkdir -p "$display_dir" "$thumb_dir"
find "$input_dir" -maxdepth 1 -type f -iname "*.jpg" -print0 |
while IFS= read -r -d '' img; do
filename=$(basename "$img")
convert "$img" -resize 1200x1200 "$display_dir/$filename"
convert "$img" -resize 150x150 "$thumb_dir/$filename"
done
echo "Generated display and thumbnail versions."
This produces two output sets from a single source directory — a larger display-ready version and a small thumbnail — in one pass.
Converting Format While Resizing
ImageMagick can also convert formats as part of the same command:
convert input.png -resize 800x600 output.jpg
This resizes a PNG and outputs it as a JPEG in a single step, which is handy when standardizing a mixed-format image library.
Real-World Use Cases
- E-commerce product photos: Standardizing dimensions across hundreds of product images before uploading to a storefront.
- Website asset optimization: Generating responsive image sizes (thumbnail, medium, large) for faster page loads.
- Photography workflows: Batch-resizing RAW-exported JPEGs for web galleries while preserving originals.
- Social media prep: Resizing images to platform-specific dimensions before scheduled posting.
- Automated content pipelines: Resizing user-uploaded images server-side as part of a web application’s processing pipeline.
Automation Example
Here’s a script I run via a folder-watching cron job to automatically resize new uploads as they arrive:
#!/bin/bash
set -euo pipefail
watch_dir="/data/uploads"
processed_dir="/data/uploads_resized"
log_file="/var/log/image_resizer.log"
mkdir -p "$processed_dir"
find "$watch_dir" -maxdepth 1 -type f -iname "*.jpg" -newer /tmp/last_run_marker -print0 |
while IFS= read -r -d '' img; do
filename=$(basename "$img")
convert "$img" -resize 1024x1024 -quality 85 "$processed_dir/$filename"
echo "$(date '+%F %T') Resized $filename" >> "$log_file"
done
touch /tmp/last_run_marker
The -newer /tmp/last_run_marker flag ensures only files added since the last run are processed, making this safe to run repeatedly via cron without reprocessing everything each time.
Best Practices
- Always output resized images to a separate directory rather than overwriting originals, to avoid irreversible quality loss.
- Preserve aspect ratio by default; only force exact dimensions when you specifically need a fixed grid layout.
- Use sensible JPEG quality settings (80–90 is usually a good balance between size and visual quality) rather than defaulting to 100.
- Batch process using
find -print0andwhile read -d ''rather than plain globs, to safely handle unusual filenames. - Log processed files when running resizing as part of an unattended, automated pipeline.
Security Considerations
- Malicious image files: Untrusted, user-uploaded images can sometimes exploit vulnerabilities in image-processing libraries. Keep ImageMagick updated to the latest patched version, and consider sandboxing processing of untrusted uploads.
- ImageMagick policy restrictions: ImageMagick ships with a
policy.xmlfile that can restrict certain operations (like reading remote URLs or specific formats) for security reasons — don’t disable these restrictions without understanding the risk, especially on servers processing public uploads. - Resource exhaustion: Extremely large or maliciously crafted images can consume excessive memory or CPU during processing (“image bombs”) — consider setting resource limits via ImageMagick’s
-limitflag. - Path traversal: Sanitize filenames from untrusted sources before using them to construct output paths.
Optimization Tips
- Use
-stripto remove metadata (EXIF data, color profiles) from images, which can meaningfully reduce file size:
convert input.jpg -resize 800x600 -strip -quality 85 output.jpg
- Process images in parallel using
xargs -Pto take advantage of multi-core systems:
find . -maxdepth 1 -iname "*.jpg" -print0 | xargs -0 -P 4 -I{} convert {} -resize 800x600 resized/{}
- For very large batches, consider
mogrify(which edits images in place, or into a specified output directory with-path) instead ofconvert, since it can be marginally faster for simple in-place batch operations.
Troubleshooting Common Issues
Problem: convert: command not found. Install ImageMagick via your package manager, and confirm with convert -version.
Problem: Resized images look distorted. You likely used the ! flag unintentionally, forcing exact dimensions and ignoring the original aspect ratio.
Problem: Output images are much larger than expected. Add -strip to remove unnecessary metadata, and adjust -quality to a lower value for JPEGs.
Problem: Script fails on filenames with spaces or special characters. Switch from a plain glob loop to find -print0 combined with while IFS= read -r -d ''.
Problem: “convert-im6.q16: not authorized” errors. This is usually due to ImageMagick’s security policy blocking certain formats (like PDF). Check /etc/ImageMagick-6/policy.xml and adjust cautiously if you understand the security implications.
Common Mistakes to Avoid
- Overwriting original images without keeping a backup, resulting in permanent quality loss.
- Forcing exact dimensions with
!when aspect-ratio-preserving resize is actually what’s needed. - Not stripping metadata, leading to unnecessarily large output files.
- Processing untrusted user uploads without any resource or format restrictions in place.
Frequently Asked Questions
Does resizing reduce image quality? Downscaling generally preserves visual quality well; it’s aggressive JPEG compression (low -quality values) or upscaling that introduces noticeable quality loss.
Can I resize images without ImageMagick? Yes, alternatives include ffmpeg (also handles images) or vipsthumbnail from libvips, which is often faster for very large batches.
How do I resize only if the image is larger than the target size? Add a > after your dimensions: convert input.jpg -resize 800x600\> output.jpg, which only shrinks images larger than the target, leaving smaller ones untouched.
Can this resize animated GIFs? Yes, but you typically need the -coalesce flag before resizing to handle each frame correctly: convert input.gif -coalesce -resize 400x400 output.gif.
What’s the difference between convert and mogrify? convert creates a new output file, while mogrify modifies images in place (or writes to a directory specified with -path) — useful for quick batch edits without managing separate output filenames.
Summary
A Bash image resizer built around ImageMagick’s convert command scales from a single one-line command to a fully automated batch-processing pipeline capable of handling thumbnails, format conversion, and quality optimization. The details that matter most: preserve aspect ratio by default, strip unnecessary metadata to save space, use find -print0 for safe filename handling, and always keep your resized output separate from your originals.
References
- ImageMagick official documentation: https://imagemagick.org/script/command-line-processing.php
- ImageMagick
resizegeometry options: https://imagemagick.org/script/command-line-processing.php#geometry - Bash Reference Manual: https://www.gnu.org/software/bash/manual/bash.html
- GNU
findmanual: https://www.gnu.org/software/findutils/manual/html_mono/find.html
