Skip to content

Instantly share code, notes, and snippets.

@itsmikita
Created March 3, 2026 00:30
Show Gist options
  • Select an option

  • Save itsmikita/be157f26f9cb9106f893b52d0e2f9655 to your computer and use it in GitHub Desktop.

Select an option

Save itsmikita/be157f26f9cb9106f893b52d0e2f9655 to your computer and use it in GitHub Desktop.
Tiny install AppImage shell script for any Linux machine
#!/usr/bin/env bash
set -e
# ---------------------------
# helpers
# ---------------------------
humanize() {
local name="$1"
name="${name%.AppImage}"
name="${name%.appimage}"
name="${name//-/ }"
name="${name//_/ }"
echo "$(tr '[:lower:]' '[:upper:]' <<< ${name:0:1})${name:1}"
}
usage() {
echo "Usage:"
echo " $0 /path/to/file.AppImage [--name NAME] [--icon ICON_PATH] [--category CATEGORY]"
exit 1
}
extract_icon() {
local appimage="$1"
local filename="$2"
local icon_store="$HOME/.local/share/icons/appimage-installer"
mkdir -p "$icon_store"
if ! MOUNT_OUTPUT=$("$appimage" --appimage-mount 2>/dev/null); then
return 1
fi
MOUNT_DIR=$(echo "$MOUNT_OUTPUT" | head -n1)
if [[ ! -d "$MOUNT_DIR" ]]; then
return 1
fi
# 1. Try .DirIcon
if [[ -f "$MOUNT_DIR/.DirIcon" ]]; then
local icon_target="$icon_store/${filename}.png"
cp "$MOUNT_DIR/.DirIcon" "$icon_target"
fusermount -u "$MOUNT_DIR" 2>/dev/null || true
echo "$icon_target"
return 0
fi
# 2. Try desktop file
DESKTOP_INTERNAL=$(find "$MOUNT_DIR" -maxdepth 2 -name "*.desktop" | head -n1)
if [[ -n "$DESKTOP_INTERNAL" ]]; then
ICON_NAME=$(grep -E '^Icon=' "$DESKTOP_INTERNAL" | head -n1 | cut -d= -f2)
if [[ -n "$ICON_NAME" ]]; then
ICON_FILE=$(find "$MOUNT_DIR" -name "${ICON_NAME}.*" | head -n1)
if [[ -f "$ICON_FILE" ]]; then
ext="${ICON_FILE##*.}"
local icon_target="$icon_store/${filename}.${ext}"
cp "$ICON_FILE" "$icon_target"
fusermount -u "$MOUNT_DIR" 2>/dev/null || true
echo "$icon_target"
return 0
fi
fi
fi
fusermount -u "$MOUNT_DIR" 2>/dev/null || true
return 1
}
# ---------------------------
# args parsing
# ---------------------------
APPIMAGE=""
NAME=""
ICON=""
CATEGORY="Utility"
while [[ $# -gt 0 ]]; do
case "$1" in
--name)
NAME="$2"
shift 2
;;
--icon)
ICON="$2"
shift 2
;;
--category)
CATEGORY="$2"
shift 2
;;
-*)
echo "Unknown flag: $1"
usage
;;
*)
if [[ -z "$APPIMAGE" ]]; then
APPIMAGE="$1"
else
usage
fi
shift
;;
esac
done
[[ -z "$APPIMAGE" ]] && usage
# ---------------------------
# validation
# ---------------------------
if [[ ! -f "$APPIMAGE" ]]; then
echo "File not found."
exit 1
fi
if [[ "$APPIMAGE" != *.AppImage && "$APPIMAGE" != *.appimage ]]; then
echo "Not an AppImage file."
exit 1
fi
# ---------------------------
# setup
# ---------------------------
BASENAME=$(basename "$APPIMAGE")
FILENAME="${BASENAME%.AppImage}"
FILENAME="${FILENAME%.appimage}"
[[ -z "$NAME" ]] && NAME=$(humanize "$BASENAME")
TARGET_DIR="$HOME/Applications"
DESKTOP_DIR="$HOME/.local/share/applications"
mkdir -p "$TARGET_DIR"
mkdir -p "$DESKTOP_DIR"
TARGET_PATH="$TARGET_DIR/$BASENAME"
cp "$APPIMAGE" "$TARGET_PATH"
chmod +x "$TARGET_PATH"
# ---------------------------
# icon handling
# ---------------------------
if [[ -z "$ICON" ]]; then
if ICON_PATH=$(extract_icon "$TARGET_PATH" "$FILENAME"); then
ICON="$ICON_PATH"
else
ICON="application-x-executable"
fi
fi
# ---------------------------
# create desktop entry
# ---------------------------
DESKTOP_FILE="$DESKTOP_DIR/$FILENAME.desktop"
cat > "$DESKTOP_FILE" <<EOF
[Desktop Entry]
Name=$NAME
Exec=$TARGET_PATH
Icon=$ICON
Type=Application
Categories=$CATEGORY;
Terminal=false
EOF
# ---------------------------
# refresh desktop database
# ---------------------------
if command -v update-desktop-database >/dev/null 2>&1; then
update-desktop-database "$DESKTOP_DIR" >/dev/null 2>&1 || true
fi
echo "Installed:"
echo " $TARGET_PATH"
echo " $DESKTOP_FILE"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment