Back to catalog

Compress JSON

convert / v1.3.0

Minify a JSON file or a directory tree of JSON files.

JSONCompressionMinifyjq

Compresses JSON with jq while preserving filenames and relative directory paths in the output directory. Accepts a single file or recursively processes a directory, reports successful and failed files, and exits with an error if any JSON input is invalid.

Requirements

  • jq

Platforms

LinuxmacOS

Usage

./scripts/compress-json.sh --input data.json --output min
./scripts/compress-json.sh -f ./data -o ./min
./scripts/compress-json.sh --input=./data --output=./build/min

Download

Install quickly or copy a command for your shell.

toolbox compress-json
curl -fsSL "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/compress-json.sh" -o "compress-json.sh"
wget -O "compress-json.sh" "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/compress-json.sh"
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/compress-json.sh" -OutFile "compress-json.sh"
python3 -c "import urllib.request; urllib.request.urlretrieve('https://raw.githubusercontent.com/PiSaucer/toolbox/main/scripts/compress-json.sh', 'compress-json.sh')"

Integrity

SHA256

31d14fe535a24f7f77a49f07b336cd5b986f6dfde8fc83ecda1120a4e0d19164

Copy and Paste Script

Use this when you want to copy the full script directly.

#!/bin/sh
# compress-json.sh
# Copyright (c) 2026 PiSaucer
# Licensed under the MIT License
# Version 1.3.0

# Compress JSON files
# Usage: ./compress-json.sh -f file|-i file [--input file] -o dir [--output dir]

# Color codes
NC='\033[0m' # No Color
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'

helpFunction() {
    printf "Compress JSON files\n\n"
    printf "Usage: ${YELLOW}$0 -f file|-i file [--input file] -o dir [--output dir] ${NC}\n"
    printf "\t-f, -i, --input   The Input JSON Filename or Directory\n"
    printf "\t-o, --output      The Output Directory (optional)\n"
    printf "\t--help            Show this help message\n"
    exit 1 # Exit script after printing help
}

# Parse long options
while [ $# -gt 0 ]; do
    case "$1" in
        --input)
            file="$2"
            shift 2
            ;;
        --input=*)
            file="${1#*=}"
            shift
            ;;
        --output)
            output="$2"
            shift 2
            ;;
        --output=*)
            output="${1#*=}"
            shift
            ;;
        --help)
            helpFunction
            ;;
        *)
            break
            ;;
    esac
done

# Parse short options
while getopts "f:o:i:" opt; do
   case "$opt" in
      f | i ) file="$OPTARG" ;;
      o ) output="$OPTARG" ;;
      ? ) helpFunction ;;
   esac
done

if [ -z "$file" ]; then
   printf "${RED}Missing Input JSON Filename or Directory${NC}\n"
   helpFunction
fi

if ! command -v jq >/dev/null 2>&1; then
    printf "${RED}Error: jq is not installed. Please install jq first.${NC}\n"
    exit 1
fi

output="${output:-./min}"
mkdir -p "$output"

compressed=0
failed=0

compress_file() {
    input_file="$1"
    output_file="$2"
    output_dir=$(dirname "$output_file")
    tmpfile="$output_file.tmp"

    mkdir -p "$output_dir"

    if jq -c . "$input_file" > "$tmpfile"; then
        mv "$tmpfile" "$output_file"
        printf "${GREEN}Compressed $input_file -> $output_file${NC}\n"
        compressed=$((compressed + 1))
    else
        printf "${RED}Failed: $input_file${NC}\n"
        rm -f "$tmpfile"
        failed=$((failed + 1))
    fi
}

if [ -d "$file" ]; then
    input_root="${file%/}"
    output_root="${output%/}"
    file_list=$(mktemp "${TMPDIR:-/tmp}/compress-json.XXXXXX") || {
        printf "${RED}Error: could not create a temporary file.${NC}\n"
        exit 1
    }
    trap 'rm -f "$file_list"' 0 1 2 15

    find "$input_root" -type f -name "*.json" > "$file_list"
    while IFS= read -r i; do
        case "$i" in
            "$output_root"/*)
                continue
                ;;
        esac

        rel="${i#"$input_root"/}"
        outfile="$output_root/$rel"

        compress_file "$i" "$outfile"
    done < "$file_list"

    rm -f "$file_list"
    trap - 0 1 2 15

elif [ -f "$file" ]; then
    base=$(basename "$file")
    outfile="${output%/}/$base"

    compress_file "$file" "$outfile"

else
    printf "${RED}Input does not exist: $file${NC}\n"
    helpFunction
fi

printf "\n${BLUE}Summary:${NC} ${GREEN}%s compressed${NC}, ${RED}%s failed${NC}\n" "$compressed" "$failed"

if [ "$failed" -gt 0 ]; then
    exit 1
fi