Share your shell/bash/bat scripts

Been really loving scripting lately…

Share your scripts here! All languages welcome, but shell scripts and bash scripts will be most useful here.

Scripts don’t have to be made by you. If you found something useful and want to share it, just make sure to give proper credit. A link to the creators page (if they have one) would suffice.

Doesn’t need to be complicated, simple automation is great too!

Format:

1. What does it do?

2. Format the script like the image below:

Screenshot_20250806-094355_org.chromium.webapk.ac2bf625dd631a7f8_v2

Installs all apk’s in /data/local/tmp, then deletes them (useful for a custom app store, with modified apks).

#!/system/bin/sh

for apk in /data/local/tmp/*.apk; do
  [ -f "$apk" ] && pm install -r "$apk" && rm "$apk"
done

Example of use:

App with a button that runs:

su -c curl -L https://github.com/TripleU613/TripleUMDM_Public/releases/download/3.4/app-release.apk -o /data/local/tmp/tumdm.apk

Then it runs the script above to install it, then delete the APK.

Bat scripts also?

Sure, I’ll edit the post.

I made a bat script to start Shizuku.

It starts Shizuku, checks if it was successful, and if it wasn’t, tries again when you press enter.

I had a bunch of versions of this script, I think this is the one that worked, but I have no patience booting into Windows to check, so if it doesn’t work let me know.

@echo off
cd {insert the path to wherever you keep platform-tools}
:start_loop
adb shell sh /storage/emulated/0/android/data/moe.shizuku.privileged.api/start.sh | find "info: shizuku_starter exit with 0"
if %ERRORLEVEL% NEQ 0 (
  echo Oops, look like something went wrong.
  echo Press enter to try again.
  pause >nul
  goto :start_loop
) else (
  echo Shizuku started successfully 
pause
)

Script to push modules and an installation script to sdcard and install them. Edit as needed. Save as .bat

adb push vMouse2.zip /sdcard/ && adb push NABHome1.2.zip /sdcard/ && adb push Volte-Wifi-Calling-Enabler.zip /sdcard/ && adb push install_magisk_modules.sh /sdcard/ && adb shell su -c "sh /sdcard/install_magisk_modules.sh"

Save this as install_magisk_modules.sh

magisk --install-module /sdcard/vMouse2.zip
magisk --install-module /sdcard/NABHome1.2.zip
magisk --install-module /sdcard/Volte-Wifi-Calling-Enabler.zip

There are more normal ways to do this, but this is all I got 5 min before Shabbos when I needed an alarm last week, but didn’t want it to play all day :joy:

My alarm was set to 9 and on snooze.

This shut off the phone at 9:15 am

#!/bin/bash

# Wait until 9:15 AM
while true; do
  if [ "$(date +%H:%M)" = "09:15" ]; then
    su -c "reboot -p"
    exit
  fi
  sleep 20
done

So late?!

:eyes:

Whoops

Download all releases from any (public) GitHub repository

This will put all files from each release neatly in labeled folders.

I’m using Termux.

pkg install jq curl
nano dl.sh

Paste the below script:

#!/bin/bash

# === SET YOUR REPOSITORY HERE ===
REPO="owner/repo"  # Example: "myusername/myproject"

# === DO NOT MODIFY BELOW THIS LINE ===
API="https://api.github.com/repos/$REPO/releases"
DEST="./$(basename "$REPO")_releases"

mkdir -p "$DEST"
cd "$DEST" || exit 1

# Fetch and process all releases
curl -s "$API" | jq -c '.[]' | while read -r release; do
    TAG=$(echo "$release" | jq -r '.tag_name')
    NAME=$(echo "$release" | jq -r '.name')
    FOLDER="${TAG:-$NAME}"
    mkdir -p "$FOLDER"

    # Download every asset for this release
    echo "$release" | jq -c '.assets[]' | while read -r asset; do
        URL=$(echo "$asset" | jq -r '.browser_download_url')
        FILENAME=$(echo "$asset" | jq -r '.name')
        echo "Downloading $FILENAME to $FOLDER/"
        curl -L --fail -o "$FOLDER/$FILENAME" "$URL"
    done
done

Press ctrl+x, y, then enter.

chmod +x dl.sh
./dl.sh

Here’s a script and cronjob to sync folders daily (3AM) to a Google Drive rclone remote. If you delete a file, it will move it to “Recycle Bin” folder on Google Drive on the next sync. You can add as many folders as you’d like.

Just made this yesterday for a work server. Script works great, cronjob will be tested overnight.

script (with log)

#!/bin/bash
set -e

# Sync a local folder to Google Drive with recycle bin for deletions
rclone sync -P /path/to/local/folder gdrive:backup/folder \
  --backup-dir=gdrive:backup/RecycleBin/folder \
  --log-file=/path/to/rclone_backup.log

# Log backup completion timestamp
echo "Google Drive backup completed at $(date)" >> /path/to/backup.log

cronjob (with log)

0 3 * * * /path/to/your_backup_script.sh >> /tmp/backup_cron.log 2>&1

I used this once :rofl:

a script to spam someone using termux. you must have already done pkg install termux-api. if youre phone isn’t rooted, cp this file to home of termux and run chmod +x filename then run it with filename number amountOfMessages. e.g. spam 8458458455 30

#!/bin/bash

if [ "$#" -ne 2 ]; then
  echo "Usage: $0 <phone_number> <number_of_messages>"
  exit 1
fi

PHONE_NUMBER="$1"
COUNT="$2"

# Loop to send the messages.
for i in $(seq 0 $((COUNT-1)))
do
  MESSAGE="spam message number $i"
  termux-sms-send -n "$PHONE_NUMBER" "$MESSAGE"
  echo "Sent message $i to $PHONE_NUMBER"
done

echo "Script finished."

or just run directly in termux:

for i in $(seq 0 30)
do
  termux-sms-send -n 1234567890 "hello. message number $i"
done

p.s. will only work with regular termux (f-droid, apkpure) not from google play

Restore data of a given app on first boot

I will be using FNG as an example. I started accessibility as well.

I put FNG in /system/priv-app with a proper permissions xml in /system/etc/permissions. This is because I didn’t want users to have to manually grant permissions.

Backup data of app

You will need to find the exact location.

adb shell
su
tar -cpf /sdcard/fluid.tar -C / data/data/com.fb.fluid

adb pull /sdcard/fluid.tar

I placed fluid.tar in /system.

Restore app data

The below is just a snippet of a larger script taken from the F21 Pro 6.1.3 ROM (/system/etc/adbdata.sh). You will need more to make sure it only runs once.

  am start -n com.fb.fluid/.ui.ActivitySettings
  sleep 0.5
  pid=$(pidof com.fb.fluid)
  [ -n "$pid" ] && kill -9 "$pid"

  OWNER=$(stat -c '%u:%g' /data/data/com.fb.fluid)
  tar -xpf /system/fluid.tar -C /
  
  chown -R "$OWNER" /data/data/com.fb.fluid

  settings put secure enabled_accessibility_services com.fb.fluid/com.fb.fluid.MainAccessibilityService
  settings put secure accessibility_enabled 1
sudo apt moo
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude moo
There are no Easter Eggs in this program.
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -v moo
There really are no Easter Eggs in this program.
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -vv moo
Didn't I already tell you that there are no Easter Eggs in this program?
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -vvv moo
Stop it!
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -vvvv moo
Okay, okay, if I give you an Easter Egg, will you go away?
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -vvvvv moo
All right, you win.

                               /----\
                       -------/      \
                      /               \
                     /                |
   -----------------/                  --------\
   ----------------------------------------------
johnw@johnw-Standard-PC-Q35-ICH9-2009:~$ aptitude -vvvvvv moo
What is it?  It's an elephant being eaten by a snake, of course.

credits: @Shalom_Karr (AI)

here is a script that probably no1 will find useful. i made it for myself mainly. Its basically an automation for running c programs on termux using clang.
normally to run a c script on an unrooted android phone you have to run clang on the script, put the output in termux directories and only there can you run chmod +x output.out, and then run it.
So i created a script to automate it with options to delete the output from termux directory which you can use if your not planning on doing subsistent compilations and also an option to copy the output to current working directory. i named it crun. You can put this in a file called crun and put it in /data/data/com.termux/files/usr/bin and run chmod +x crum, and then you can run it from anywhere directory.

#!/data/data/com.termux/files/usr/bin/bash

set -e

if [ -z "$1" ]; then
  echo "run crun -h for usage"
  exit 1
fi

while [ $# -gt 0 ]; do
 case "$1" in
  -h|--help)
   echo -e "usage: crun [-sd] <source.c>\ncopies c script to termux home, executes and keeps the output to make quicker subsiquent compilations unless used with option -d which then deletes the output. option -s saves output also to current dir.\ncredits: @flipphoneguy"
   exit 0
   ;;
  -s)
   SFLAG=true
   ;;
  -d)
   DFLAG=true
   ;;
  -sd|-ds)
   SFLAG=true
   DFLAG=true
   ;;
  -*)
   echo "invalid option '$1'"
   exit 1
   ;;
  *)
   if [ "$FILE" ]; then
    echo "only accepts 1 file argument but more were given."
    exit 1
   fi
   FILE="$1"
   ;;
 esac
 shift
done


if [ ! -f "$FILE" ]; then
  echo "Error: file '$FILE' not found."
  exit 1
fi

OUT="/data/data/com.termux/files/home/c/${FILE}.o"
mkdir -p /data/data/com.termux/files/home/c
clang "$FILE" -o "$OUT"
chmod +x "$OUT"
"$OUT"

if [ "$SFLAG" = "true" ]; then
  cp "$OUT" "."
fi
if [ "$DFLAG" = "true" ]; then
  rm "$OUT"
fi
exit 0

Been using these on termux when I’m too lazy to leave my bed. Repacking has not been extensively tested. Haven’t flashed any yet.

If someone made a TUI, that’d be cool.

install-dependencies.sh
#!/bin/bash

# Android ROM Tools - Termux Dependency Installer
# Installs all required packages for unpacking/repacking Android images

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

print_header() {
    echo -e "${CYAN}================================${NC}"
    echo -e "${CYAN}$1${NC}"
    echo -e "${CYAN}================================${NC}"
}

# Check if running in Termux
if [ ! -d "/data/data/com.termux" ]; then
    print_error "This script is designed for Termux only"
    exit 1
fi

print_header "Android ROM Tools Installer"
echo ""
print_info "This script will install all dependencies for:"
echo "  - super.img unpacking/repacking"
echo "  - ext4 partition unpacking/repacking"
echo ""

# Update package lists
print_info "Updating package lists..."
pkg update -y

# Install required packages
print_header "Installing Required Packages"

PACKAGES=(
    # Core utilities
    "coreutils"

    # Sparse image tools
    "android-tools"  # Contains simg2img, img2simg, lpunpack, lpmake, etc.

    # ext4 filesystem tools
    "e2fsprogs"      # Contains debugfs, mke2fs, etc.

    # Additional utilities
    "util-linux"     # Contains various utilities
)

for pkg in "${PACKAGES[@]}"; do
    print_info "Installing $pkg..."
    pkg install -y "$pkg" 2>/dev/null || print_warn "$pkg may already be installed or unavailable"
done

echo ""
print_header "Verifying Installation"

# Verify tools are installed
TOOLS=(
    "simg2img:Sparse to raw image converter"
    "img2simg:Raw to sparse image converter"
    "lpunpack:Super partition unpacker"
    "lpmake:Super partition creator"
    "debugfs:ext4 filesystem debugger/extractor"
    "mke2fs.android:Android ext4 filesystem creator"
    "e2fsdroid:ext4 image populator"
    "ext2simg:ext4 to sparse converter"
)

ALL_OK=1
for tool_info in "${TOOLS[@]}"; do
    tool="${tool_info%%:*}"
    desc="${tool_info#*:}"
    if command -v "$tool" &> /dev/null; then
        echo -e "  ${GREEN}✓${NC} $tool - $desc"
    else
        echo -e "  ${RED}✗${NC} $tool - $desc (NOT FOUND)"
        ALL_OK=0
    fi
done

echo ""

if [ "$ALL_OK" -eq 1 ]; then
    print_header "Installation Complete!"
    echo ""
    print_info "All tools installed successfully."
    echo ""
    echo "Available scripts:"
    echo "  ./unpack_super.sh  - Unpack super.img to partition images"
    echo "  ./repack_super.sh  - Repack partition images to super.img"
    echo "  ./unpack_ext4.sh   - Extract files from ext4 images"
    echo "  ./repack_ext4.sh   - Create ext4 images from directories"
    echo ""
    echo "Example workflow:"
    echo "  1. ./unpack_super.sh super.img"
    echo "  2. ./unpack_ext4.sh super_unpacked/system_a.img"
    echo "  3. (make modifications)"
    echo "  4. ./repack_ext4.sh system_a_extracted -o system_a.img"
    echo "  5. ./repack_super.sh super_unpacked -o super_new.img -s"
else
    print_error "Some tools could not be installed."
    print_error "Try running 'pkg update && pkg upgrade' first."
fi
unpack-super.sh
#!/bin/bash

# Android super.img unpacker script
# Handles both sparse and raw super images

set -e

RAW_IMG=""

# Cleanup function to ensure super_raw.img is always deleted
cleanup() {
    if [ -n "$RAW_IMG" ] && [ -f "$RAW_IMG" ]; then
        rm -f "$RAW_IMG"
    fi
}

# Trap to run cleanup on exit, error, or interrupt
trap cleanup EXIT ERR INT TERM

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <super.img> [output_directory]"
    echo ""
    echo "Arguments:"
    echo "  super.img         Path to the super.img file to unpack"
    echo "  output_directory  Optional output directory (default: <super_name>_unpacked)"
    exit 1
}

# Check arguments
if [ $# -lt 1 ]; then
    usage
fi

INPUT_IMG="$1"
INPUT_NAME=$(basename "$INPUT_IMG" .img)

# Set output directory
if [ -n "$2" ]; then
    OUTPUT_DIR="$2"
else
    OUTPUT_DIR="$(dirname "$INPUT_IMG")/${INPUT_NAME}_unpacked"
fi

# Check if input file exists
if [ ! -f "$INPUT_IMG" ]; then
    print_error "File not found: $INPUT_IMG"
    exit 1
fi

# Check for required tools
for tool in lpunpack simg2img; do
    if ! command -v $tool &> /dev/null; then
        print_error "$tool is required but not installed."
        exit 1
    fi
done

# Create output directory
print_info "Creating output directory: $OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

# Check if image is sparse by reading magic bytes
# Sparse magic: 0xed26ff3a (little-endian: 3a ff 26 ed)
MAGIC=$(od -A n -t x1 -N 4 "$INPUT_IMG" | tr -d ' ')

if [ "$MAGIC" = "3aff26ed" ]; then
    print_info "Detected sparse image format"
    print_info "Converting sparse image to raw..."

    RAW_IMG="$OUTPUT_DIR/super_raw.img"
    simg2img "$INPUT_IMG" "$RAW_IMG"

    print_info "Conversion complete"
    UNPACK_IMG="$RAW_IMG"
    CLEANUP_RAW=1
else
    print_info "Detected raw image format"
    UNPACK_IMG="$INPUT_IMG"
    CLEANUP_RAW=0
fi

# Unpack partitions
print_info "Unpacking partitions with lpunpack..."
lpunpack "$UNPACK_IMG" "$OUTPUT_DIR"

# Delete super_raw.img after unpacking
if [ -n "$RAW_IMG" ] && [ -f "$RAW_IMG" ]; then
    print_info "Deleting intermediate file: super_raw.img"
    rm -f "$RAW_IMG"
fi

# List extracted partitions
echo ""
print_info "Extraction complete! Partitions extracted to: $OUTPUT_DIR"
echo ""
echo "Extracted partitions:"
ls -lh "$OUTPUT_DIR"/*.img 2>/dev/null || print_warn "No partition images found"
unpack_ext4.sh
#!/bin/bash

# Android ext4 image unpacker script
# Extracts contents from ext4 partition images without root

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <image.img> [output_directory]"
    echo ""
    echo "Arguments:"
    echo "  image.img          Path to ext4 image file (system, vendor, product, etc.)"
    echo "  output_directory   Optional output directory (default: <image_name>_extracted)"
    echo ""
    echo "Examples:"
    echo "  $0 system_a.img"
    echo "  $0 vendor_a.img vendor_extracted"
    exit 1
}

# Check arguments
if [ $# -lt 1 ]; then
    usage
fi

INPUT_IMG="$1"
INPUT_NAME=$(basename "$INPUT_IMG" .img)

# Set output directory
if [ -n "$2" ]; then
    OUTPUT_DIR="$2"
else
    OUTPUT_DIR="$(dirname "$INPUT_IMG")/${INPUT_NAME}_extracted"
fi

# Check if input file exists
if [ ! -f "$INPUT_IMG" ]; then
    print_error "File not found: $INPUT_IMG"
    exit 1
fi

# Check for required tools
if ! command -v debugfs &> /dev/null; then
    print_error "debugfs is required but not installed."
    print_error "Install with: pkg install e2fsprogs"
    exit 1
fi

# Verify it's an ext4 image by checking magic at offset 0x438
MAGIC=$(od -A n -t x1 -N 2 -j 1080 "$INPUT_IMG" | tr -d ' ')
if [ "$MAGIC" != "53ef" ]; then
    print_error "Not a valid ext4 image (magic: $MAGIC, expected: 53ef)"
    print_error "This might be erofs or another filesystem type"
    exit 1
fi

print_info "Valid ext4 image detected"

# Create output directory
print_info "Creating output directory: $OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

# Get absolute path for output
OUTPUT_DIR=$(cd "$OUTPUT_DIR" && pwd)

# Extract using debugfs
print_info "Extracting files from $INPUT_IMG..."
print_info "This may take a while for large images..."

# Use debugfs to recursively dump all contents
debugfs -R "rdump / \"$OUTPUT_DIR\"" "$INPUT_IMG" 2>&1 | grep -v "^debugfs:" || true

# Count extracted files
FILE_COUNT=$(find "$OUTPUT_DIR" -type f 2>/dev/null | wc -l)
DIR_COUNT=$(find "$OUTPUT_DIR" -type d 2>/dev/null | wc -l)
LINK_COUNT=$(find "$OUTPUT_DIR" -type l 2>/dev/null | wc -l)

echo ""
print_info "Extraction complete!"
print_info "Output directory: $OUTPUT_DIR"
print_info "Files: $FILE_COUNT | Directories: $DIR_COUNT | Symlinks: $LINK_COUNT"

# Show top-level contents
echo ""
echo "Top-level contents:"
ls -la "$OUTPUT_DIR" 2>/dev/null | head -20
repack_partition.sh
#!/bin/bash

# Android partition repacker script
# Repacks extracted directories back to ext4 images (sparse or raw)

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <input_directory> [options]"
    echo ""
    echo "Arguments:"
    echo "  input_directory    Directory containing extracted filesystem"
    echo ""
    echo "Options:"
    echo "  -o, --output FILE  Output image file (default: <dir_name>.img)"
    echo "  -s, --size SIZE    Exact image size in bytes (default: auto-calculated)"
    echo "  -S, --sparse       Output sparse image instead of raw"
    echo "  -h, --help         Show this help"
    echo ""
    echo "Examples:"
    echo "  $0 system_a_extracted"
    echo "  $0 vendor_a_extracted -o vendor_new.img -S"
    echo "  $0 product_a_extracted -s 734003200 -S"
    exit 1
}

# Default values
OUTPUT_FILE=""
IMG_SIZE=""
SPARSE=0

# Parse arguments
INPUT_DIR=""
while [[ $# -gt 0 ]]; do
    case $1 in
        -o|--output)
            OUTPUT_FILE="$2"
            shift 2
            ;;
        -s|--size)
            IMG_SIZE="$2"
            shift 2
            ;;
        -S|--sparse)
            SPARSE=1
            shift
            ;;
        -h|--help)
            usage
            ;;
        -*)
            print_error "Unknown option: $1"
            usage
            ;;
        *)
            if [ -z "$INPUT_DIR" ]; then
                INPUT_DIR="$1"
            else
                print_error "Unexpected argument: $1"
                usage
            fi
            shift
            ;;
    esac
done

# Check input directory
if [ -z "$INPUT_DIR" ]; then
    print_error "Input directory is required"
    usage
fi

# Remove trailing slash
INPUT_DIR="${INPUT_DIR%/}"

if [ ! -d "$INPUT_DIR" ]; then
    print_error "Directory not found: $INPUT_DIR"
    exit 1
fi

# Set default output file
if [ -z "$OUTPUT_FILE" ]; then
    DIR_NAME=$(basename "$INPUT_DIR" | sed 's/_extracted$//')
    OUTPUT_FILE="${DIR_NAME}.img"
fi

# Check for required tools
for tool in mke2fs e2fsdroid; do
    if ! command -v $tool &> /dev/null; then
        print_error "$tool is required but not installed."
        exit 1
    fi
done

# Calculate directory size if not specified
if [ -z "$IMG_SIZE" ]; then
    print_info "Calculating directory size..."
    # Get actual content size
    CONTENT_SIZE=$(du -sb "$INPUT_DIR" | cut -f1)

    # Calculate with overhead for ext4 metadata (~5-10%)
    # Also ensure minimum size and 4K alignment
    OVERHEAD=$((CONTENT_SIZE / 10))
    [ "$OVERHEAD" -lt 10485760 ] && OVERHEAD=10485760  # Min 10MB overhead

    IMG_SIZE=$((CONTENT_SIZE + OVERHEAD))

    # Align to 4K blocks
    IMG_SIZE=$(( (IMG_SIZE + 4095) / 4096 * 4096 ))

    print_info "Content size: $(numfmt --to=iec $CONTENT_SIZE 2>/dev/null || echo $CONTENT_SIZE)"
    print_info "Image size (with overhead): $(numfmt --to=iec $IMG_SIZE 2>/dev/null || echo $IMG_SIZE)"
fi

# Calculate block count (4K blocks)
BLOCK_COUNT=$((IMG_SIZE / 4096))

print_info "Creating ext4 image: $OUTPUT_FILE"
print_info "Size: $IMG_SIZE bytes ($BLOCK_COUNT blocks)"

# Remove existing output file
rm -f "$OUTPUT_FILE"

# Create ext4 filesystem (no journal, like Android images)
print_info "Creating ext4 filesystem..."
mke2fs -t ext4 -b 4096 -m 0 -O ^has_journal,^metadata_csum -L "/" "$OUTPUT_FILE" "$BLOCK_COUNT" 2>&1 | grep -v "^$" || true

# Populate with e2fsdroid
print_info "Populating image with files..."
e2fsdroid -e -a / -f "$INPUT_DIR" "$OUTPUT_FILE"

# Convert to sparse if requested
if [ "$SPARSE" -eq 1 ]; then
    if command -v img2simg &> /dev/null; then
        print_info "Converting to sparse image..."
        TEMP_FILE="${OUTPUT_FILE}.raw"
        mv "$OUTPUT_FILE" "$TEMP_FILE"
        img2simg "$TEMP_FILE" "$OUTPUT_FILE"
        rm -f "$TEMP_FILE"
        print_info "Output format: sparse"
    else
        print_warn "img2simg not found, keeping raw image"
    fi
else
    print_info "Output format: raw"
fi

echo ""
print_info "Image created successfully: $OUTPUT_FILE"
ls -lh "$OUTPUT_FILE"
repack-super.sh
#!/bin/bash

# Android super.img repacker script
# Repacks partition images into a super.img (sparse or raw)

set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

print_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

print_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

print_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

usage() {
    echo "Usage: $0 <input_directory> [options]"
    echo ""
    echo "Arguments:"
    echo "  input_directory     Directory containing partition .img files"
    echo ""
    echo "Options:"
    echo "  -o, --output FILE   Output file (default: super_repacked.img)"
    echo "  -s, --sparse        Output sparse image (default: raw)"
    echo "  -S, --size SIZE     Super partition size in bytes (default: auto)"
    echo "  -g, --group NAME    Partition group name (default: main)"
    echo "  -G, --group-size SZ Group size in bytes (default: auto)"
    echo "  -m, --metadata SIZE Metadata size (default: 65536)"
    echo "  -l, --slots COUNT   Metadata slots (default: 2)"
    echo "  -h, --help          Show this help"
    exit 1
}

# Default values
OUTPUT_FILE="super_repacked.img"
SPARSE=0
SUPER_SIZE="auto"
GROUP_NAME="main"
GROUP_SIZE=""
METADATA_SIZE=65536
METADATA_SLOTS=2

# Parse arguments
INPUT_DIR=""
while [[ $# -gt 0 ]]; do
    case $1 in
        -o|--output)
            OUTPUT_FILE="$2"
            shift 2
            ;;
        -s|--sparse)
            SPARSE=1
            shift
            ;;
        -S|--size)
            SUPER_SIZE="$2"
            shift 2
            ;;
        -g|--group)
            GROUP_NAME="$2"
            shift 2
            ;;
        -G|--group-size)
            GROUP_SIZE="$2"
            shift 2
            ;;
        -m|--metadata)
            METADATA_SIZE="$2"
            shift 2
            ;;
        -l|--slots)
            METADATA_SLOTS="$2"
            shift 2
            ;;
        -h|--help)
            usage
            ;;
        -*)
            print_error "Unknown option: $1"
            usage
            ;;
        *)
            if [ -z "$INPUT_DIR" ]; then
                INPUT_DIR="$1"
            else
                print_error "Unexpected argument: $1"
                usage
            fi
            shift
            ;;
    esac
done

# Check input directory
if [ -z "$INPUT_DIR" ]; then
    print_error "Input directory is required"
    usage
fi

if [ ! -d "$INPUT_DIR" ]; then
    print_error "Directory not found: $INPUT_DIR"
    exit 1
fi

# Check for required tools
if ! command -v lpmake &> /dev/null; then
    print_error "lpmake is required but not installed."
    exit 1
fi

# Find partition images
print_info "Scanning for partition images in: $INPUT_DIR"
PARTITIONS=()
PARTITION_ARGS=""
IMAGE_ARGS=""
TOTAL_SIZE=0

for img in "$INPUT_DIR"/*.img; do
    [ -f "$img" ] || continue

    # Skip super_raw.img if present
    basename_img=$(basename "$img")
    if [ "$basename_img" = "super_raw.img" ]; then
        continue
    fi

    # Get partition name (remove .img extension)
    part_name="${basename_img%.img}"

    # Get file size
    file_size=$(stat -c%s "$img" 2>/dev/null || stat -f%z "$img" 2>/dev/null)

    PARTITIONS+=("$part_name")
    TOTAL_SIZE=$((TOTAL_SIZE + file_size))

    print_info "Found partition: $part_name ($(numfmt --to=iec $file_size 2>/dev/null || echo $file_size bytes))"

    # Build lpmake arguments
    PARTITION_ARGS="$PARTITION_ARGS -p ${part_name}:readonly:${file_size}:${GROUP_NAME}"
    IMAGE_ARGS="$IMAGE_ARGS -i ${part_name}=${img}"
done

if [ ${#PARTITIONS[@]} -eq 0 ]; then
    print_error "No partition images found in $INPUT_DIR"
    exit 1
fi

print_info "Total partitions: ${#PARTITIONS[@]}"
print_info "Total size: $(numfmt --to=iec $TOTAL_SIZE 2>/dev/null || echo $TOTAL_SIZE bytes)"

# Calculate group size if not specified
if [ -z "$GROUP_SIZE" ]; then
    # Add 10% overhead for alignment
    GROUP_SIZE=$((TOTAL_SIZE + TOTAL_SIZE / 10))
fi

# Build lpmake command
LPMAKE_CMD="lpmake"
LPMAKE_CMD="$LPMAKE_CMD -d $SUPER_SIZE"
LPMAKE_CMD="$LPMAKE_CMD -m $METADATA_SIZE"
LPMAKE_CMD="$LPMAKE_CMD -s $METADATA_SLOTS"
LPMAKE_CMD="$LPMAKE_CMD -g ${GROUP_NAME}:${GROUP_SIZE}"
LPMAKE_CMD="$LPMAKE_CMD $PARTITION_ARGS"
LPMAKE_CMD="$LPMAKE_CMD $IMAGE_ARGS"
LPMAKE_CMD="$LPMAKE_CMD -o $OUTPUT_FILE"

if [ "$SPARSE" -eq 1 ]; then
    LPMAKE_CMD="$LPMAKE_CMD -S"
    print_info "Output format: sparse"
else
    LPMAKE_CMD="$LPMAKE_CMD -F"
    print_info "Output format: raw"
fi

# Execute lpmake
print_info "Creating super.img..."
echo ""
eval $LPMAKE_CMD

echo ""
print_info "Super image created: $OUTPUT_FILE"
ls -lh "$OUTPUT_FILE"

With all of the above in a zip:

termux-rom-tools.zip (7.2 KB)

Forget about the above… It’s nice, but:

https://github.com/Zoniik/Super-Image-Tool

Installs a script that looks up cloudflare IPs and adds them to the ufw allow list; makes it executable, and runs it every Monday

sudo bash -c "cat << 'EOF' > /root/update-cloudflare.sh
#!/bin/bash

# 1. Download the latest IP lists from Cloudflare
wget -q https://www.cloudflare.com/ips-v4 -O /tmp/cf_ips_v4
wget -q https://www.cloudflare.com/ips-v6 -O /tmp/cf_ips_v6

# 2. Allow IPv4 IPs
for ip in \`cat /tmp/cf_ips_v4\`; do
    ufw allow proto tcp from \$ip to any port 80,443 comment 'Cloudflare IPv4'
done

# 3. Allow IPv6 IPs
for ip in \`cat /tmp/cf_ips_v6\`; do
    ufw allow proto tcp from \$ip to any port 80,443 comment 'Cloudflare IPv6'
done

# 4. Clean up and Reload
rm /tmp/cf_ips_v4 /tmp/cf_ips_v6
ufw reload > /dev/null
echo 'Cloudflare IPs updated successfully.'
EOF

chmod +x /root/update-cloudflare.sh

# Safely add to crontab (prevents duplicates)
(crontab -l 2>/dev/null | grep -v '/root/update-cloudflare.sh'; echo '0 3 * * 1 /root/update-cloudflare.sh') | crontab -

echo 'Success: Script created and Cron job scheduled.'"

Cloudflare IPs change. This makes sure that your website remains active

For Windows. Not everyone is a Linux junkie.
[Guide] [Windows] Compile make_ext4fs, simg2img and img2simg using mingw [by JamFlux] | XDA Forums
I used the precompiled files that the fellow in the second post uploaded to google drive.