Created
January 22, 2026 04:34
-
-
Save robertsinfosec/7ee341de734745a820088109189e6c56 to your computer and use it in GitHub Desktop.
Simple script to install the MiniIO (S3-compatible storage) command-line tool `mc`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| # Colored, prefixed logging | |
| COLOR_RESET="\033[0m" | |
| COLOR_CYAN="\033[1;36m" | |
| COLOR_RED="\033[1;31m" | |
| COLOR_GREEN="\033[1;32m" | |
| COLOR_AMBER="\033[0;33m" | |
| log_info() { printf "%b[*] %b%s%b\n" "$COLOR_CYAN" "$COLOR_RESET" "$1" ""; } | |
| log_success() { printf "%b[+] %b%s%b\n" "$COLOR_GREEN" "$COLOR_RESET" "$1" ""; } | |
| log_warn() { printf "%b[!] %b%s%b\n" "$COLOR_AMBER" "$COLOR_RESET" "$1" ""; } | |
| log_error() { printf "%b[-] %b%s%b\n" "$COLOR_RED" "$COLOR_RESET" "$1" ""; } | |
| # Defaults | |
| DEST="/usr/local/bin/mc" | |
| TMPDIR="${TMPDIR:-/tmp}" | |
| FORCE=0 | |
| usage() { | |
| cat <<EOF | |
| Usage: $(basename "$0") [--force] [--dest /path/to/mc] | |
| Installs the MinIO mc CLI to $DEST by default. | |
| --force Overwrite existing installation without prompting. | |
| --dest Destination path (default: $DEST) | |
| -h, --help Show this help. | |
| EOF | |
| exit 1 | |
| } | |
| # Parse args (simple) | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| --force) FORCE=1; shift ;; | |
| --dest) DEST="$2"; shift 2 ;; | |
| -h|--help) usage ;; | |
| *) log_error "Unknown arg: $1"; usage ;; | |
| esac | |
| done | |
| # Ensure running as root (or writable DEST) | |
| if ! [ -w "$(dirname "$DEST")" ] && [ "$(id -u)" -ne 0 ]; then | |
| log_error "Must be run as root or with write permission to $(dirname "$DEST"). Use sudo." | |
| exit 1 | |
| fi | |
| # Check dependencies | |
| if ! command -v curl >/dev/null 2>&1; then | |
| log_error "curl is required but not installed." | |
| exit 1 | |
| fi | |
| if ! command -v uname >/dev/null 2>&1; then | |
| log_error "uname is required but missing." | |
| exit 1 | |
| fi | |
| log_info "Attempting to detect architecture..." | |
| ARCH=$(uname -m || true) | |
| case "$ARCH" in | |
| x86_64) URL="https://dl.min.io/client/mc/release/linux-amd64/mc"; ARCH_LABEL="x86_64" ;; | |
| aarch64) URL="https://dl.min.io/client/mc/release/linux-arm64/mc"; ARCH_LABEL="aarch64" ;; | |
| arm64) URL="https://dl.min.io/client/mc/release/linux-arm64/mc"; ARCH_LABEL="arm64" ;; | |
| ppc64le) URL="https://dl.min.io/client/mc/release/linux-ppc64le/mc"; ARCH_LABEL="ppc64le" ;; | |
| s390x) URL="https://dl.min.io/client/mc/release/linux-s390x/mc"; ARCH_LABEL="s390x" ;; | |
| *) | |
| log_error "Unsupported architecture: $ARCH" | |
| exit 1 | |
| ;; | |
| esac | |
| log_success "Architecture ${ARCH_LABEL} detected." | |
| # Already installed? | |
| if command -v mc >/dev/null 2>&1; then | |
| INST_PATH=$(command -v mc) | |
| INST_VER=$(mc --version 2>/dev/null || echo "unknown") | |
| log_info "Detected existing mc at ${INST_PATH} (${INST_VER})." | |
| if [ "$FORCE" -ne 1 ]; then | |
| printf "%b" "${COLOR_CYAN}" | |
| read -r -p "[*] Overwrite and install to ${DEST}? (y/N) " REPLY | |
| printf "%b" "${COLOR_RESET}" | |
| REPLY=${REPLY:-N} | |
| if [[ ! "$REPLY" =~ ^[Yy]$ ]]; then | |
| log_info "Aborting; existing installation preserved." | |
| exit 0 | |
| fi | |
| else | |
| log_info "--force supplied; will overwrite existing installation." | |
| fi | |
| fi | |
| log_info "Attempting to download ${ARCH_LABEL} executable from: ${URL}..." | |
| # Create secure temp file | |
| TMPFILE=$(mktemp --tmpdir="$TMPDIR" mc.XXXXXX) || { log_error "Failed to create temp file"; exit 1; } | |
| cleanup() { | |
| rm -f "$TMPFILE" | |
| } | |
| trap cleanup EXIT | |
| # Download | |
| if ! curl -fsSL --location "$URL" -o "$TMPFILE"; then | |
| log_error "Download failed from: $URL" | |
| exit 1 | |
| fi | |
| # Validate minimal size (non-empty, heuristic) | |
| if [ ! -s "$TMPFILE" ] || [ "$(stat -c%s "$TMPFILE")" -lt 10240 ]; then | |
| log_error "Downloaded file is empty or unexpectedly small." | |
| exit 1 | |
| fi | |
| # Atomic install: write to temporary dest then move | |
| DEST_DIR=$(dirname "$DEST") | |
| mkdir -p "$DEST_DIR" | |
| CHOWN_CMD="" | |
| if [ "$(id -u)" -eq 0 ]; then | |
| # preserve mode and owner root | |
| INSTALL_TMP="${DEST}.tmp.$$" | |
| if ! mv "$TMPFILE" "$INSTALL_TMP"; then | |
| log_error "Failed to move temporary file to ${INSTALL_TMP}" | |
| exit 1 | |
| fi | |
| chmod 0755 "$INSTALL_TMP" | |
| if ! mv -f "$INSTALL_TMP" "$DEST"; then | |
| log_error "Failed to move ${INSTALL_TMP} to ${DEST}" | |
| exit 1 | |
| fi | |
| else | |
| # non-root: try install by cp | |
| if ! cp "$TMPFILE" "$DEST"; then | |
| log_error "Failed to copy file to ${DEST}; need root privileges." | |
| exit 1 | |
| fi | |
| chmod 0755 "$DEST" | |
| fi | |
| # Verify install works | |
| if ! "$DEST" --version >/dev/null 2>&1; then | |
| log_error "Installed binary at ${DEST} failed to execute." | |
| exit 1 | |
| fi | |
| log_success "mc installed to ${DEST}." | |
| log_success "$DEST --version: $("$DEST" --version | head -n1)" | |
| exit 0 | |
| ``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment