Sharing BTT version and Mac specs is critical to receive help from this community, especially given the recent Sequoia macOS update... but it's annoying to find, copy & paste.
**Device information:**
- Type of Mac:
- macOS version:
- BetterTouchTool version: (please post the exact version - not just "the latest one")
I made this process easy by writing a script to automatically obtain this information.
Whenever I type /BTTD
, it is replaced by:
Device: MacBook Pro (14-inch, 2021)
macOS: 15.0 (24A335)
BTT Version: 4.702 (2024091705)
Alpha: 6 update(s) behind latest Alpha version 4.709 (2024091807).
Regular: Installed version is ahead of latest Regular version 4.701.
After updating BTT to the latest Alpha version, if I type /BTTD
, it gets replaced by:
Device: MacBook Pro (14-inch, 2021)
macOS: 15.0 (24A335)
BTT Version: 4.709 (2024091807)
Alpha: 0 update(s) behind latest Alpha version 4.709 (2024091807).
Regular: Installed version is ahead of latest Regular version 4.701.
Note: I use KM text replacement instead of Key Sequences in BTT because I find KM's text replacement more reliable.
Here's the script:
#!/bin/bash
###############################################################################
# BetterTouchTool Version Checker CLI
# A robust command-line interface (CLI) tool to check the installed version of
# BetterTouchTool (BTT) on macOS, compare it with the latest available alpha and
# regular (stable) versions, and provide a status update. It also retrieves
# system information and optionally copies the output to the clipboard.
#
# Usage:
# ./btt_version_checker.sh [options]
#
# Options:
# -v, --installed-version VERSION Manually specify the installed BTT version number (e.g., 4.702)
# -b, --installed-build BUILD Manually specify the installed BTT build number (e.g., 2024091705)
# -l, --log-level LEVEL Set the logging level (NONE, ERROR, INFO, DEBUG). Default: NONE
# -o, --output-format FORMAT Set output format (markdown, plain, json). Default: markdown
# -c, --copy Copy output to clipboard (enabled by default)
# -n, --no-copy Do not copy output to clipboard
# -h, --help Display this help message and exit
#
# Examples:
# 1. Run the script without arguments (auto-detect installed BTT version):
# ./btt_version_checker.sh
#
# 2. Specify the installed BTT version and build manually:
# ./btt_version_checker.sh -v 4.702 -b 2024091705
#
# 3. Set log level to DEBUG and output format to plain text:
# ./btt_version_checker.sh -l DEBUG -o plain
#
# 4. Set output format to JSON and disable copying to clipboard:
# ./btt_version_checker.sh -o json -n
#
# Notes:
# - The script requires internet access to fetch the latest BTT versions.
# - The output is formatted using Markdown by default.
# - The output is copied to the clipboard by default. Use '-n' to disable.
#
# Author: fortred2 https://community.folivora.ai/u/fortred2/summary
# Date: 2024-09-19
# Version: 1.0.0
###############################################################################
# Default configurations
log_level="NONE" # Options: NONE, ERROR, INFO, DEBUG
output_format="markdown" # Options: markdown, plain, json
copy_to_clipboard=true # Set to false with '-n' or '--no-copy'
# Initialize variables for installed version and build
installed_version=""
installed_build=""
# Required utilities
required_utilities=(
"curl"
"grep"
"awk"
"sed"
"ioreg"
"defaults"
"/usr/libexec/PlistBuddy"
"sw_vers"
"pbcopy"
)
# Function to display usage instructions
usage() {
cat << EOF
Usage: $0 [options]
Options:
-v, --installed-version VERSION Manually specify the installed BTT version number (e.g., 4.702)
-b, --installed-build BUILD Manually specify the installed BTT build number (e.g., 2024091705)
-l, --log-level LEVEL Set the logging level (NONE, ERROR, INFO, DEBUG). Default: NONE
-o, --output-format FORMAT Set output format (markdown, plain, json). Default: markdown
-c, --copy Copy output to clipboard (enabled by default)
-n, --no-copy Do not copy output to clipboard
-h, --help Display this help message and exit
Examples:
$0 # Auto-detect installed BTT version
$0 -v 4.702 -b 2024091705 # Specify installed BTT version and build
$0 -l DEBUG -o plain # Set log level to DEBUG and output format to plain text
$0 -o json -n # Set output format to JSON and do not copy to clipboard
EOF
exit 1
}
# Function to map log levels to numeric values
log_level_num() {
case "$1" in
"NONE") echo -1 ;;
"ERROR") echo 0 ;;
"INFO") echo 1 ;;
"DEBUG") echo 2 ;;
*) echo -1 ;; # Default to NONE
esac
}
# Logging function
log() {
local level=$1
local message=$2
local current_level
current_level=$(log_level_num "$log_level")
local message_level
message_level=$(log_level_num "$level")
if [ "$current_level" -ge "$message_level" ]; then
echo "[$level] $message" >&2
fi
}
# Function to check for required utilities and log their paths
check_requirements() {
local missing_utilities=()
for util in "${required_utilities[@]}"; do
local util_path
util_path=$(command -v "$util")
if [ -x "$util_path" ]; then
log "DEBUG" "Found utility '$util' at '$util_path'"
else
echo "ERROR" "Required utility '$util' not found in PATH."
missing_utilities+=("$util")
fi
done
if [ "${#missing_utilities[@]}" -ne 0 ]; then
echo "ERROR" "The following required utilities are missing: ${missing_utilities[*]}"
exit 1
fi
}
# Function to compare version numbers
version_compare() {
# Returns 1 if $1 > $2, 0 if equal, -1 if $1 < $2
local ver1="$1"
local ver2="$2"
IFS='.' read -ra ver1_parts <<< "$ver1"
IFS='.' read -ra ver2_parts <<< "$ver2"
local max_index=$(( ${#ver1_parts[@]} > ${#ver2_parts[@]} ? ${#ver1_parts[@]} : ${#ver2_parts[@]} ))
for ((i=0; i<max_index; i++)); do
local part1=${ver1_parts[i]:-0}
local part2=${ver2_parts[i]:-0}
if ((10#$part1 > 10#$part2)); then
echo 1
return
elif ((10#$part1 < 10#$part2)); then
echo -1
return
fi
done
echo 0
}
# Function to fetch the installed BTT version
get_installed_version() {
if [ -z "$installed_version" ] || [ -z "$installed_build" ]; then
# Attempt to read the installed version from BTT's Info.plist
installed_version=$(defaults read "/Applications/BetterTouchTool.app/Contents/Info.plist" CFBundleShortVersionString 2>/dev/null)
installed_build=$(defaults read "/Applications/BetterTouchTool.app/Contents/Info.plist" CFBundleVersion 2>/dev/null)
fi
# Check if installed version and build are available
if [ -z "$installed_version" ] || [ -z "$installed_build" ]; then
echo "ERROR" "BetterTouchTool is not installed, Info.plist is inaccessible, or installed version/build not specified."
exit 1
fi
installed_version_full="$installed_version ($installed_build)"
installed_version_number="$installed_version"
log "DEBUG" "Installed version is $installed_version_full"
}
# Function to fetch available alpha versions
fetch_alpha_versions() {
log "INFO" "Fetching available alpha versions..."
available_versions=$(curl -s https://folivora.ai/releases/ | grep -o 'btt[0-9]\+\.[0-9]\+-[0-9]\+\.zip' | sort -V | tail -r | uniq)
formatted_versions=$(echo "$available_versions" | sed -E 's/btt([0-9]+\.[0-9]+)-([0-9]+)\.zip/\1 (\2)/')
# Get the latest alpha version
latest_alpha_version=$(echo "$formatted_versions" | head -n 1)
log "DEBUG" "Available alpha versions: $(echo "$formatted_versions" | head -n 10 | tr '\n' ' ')"
}
# Function to determine alpha version status
determine_alpha_status() {
# Find the index of the installed version in the list of available alpha versions
installed_index=$(echo "$formatted_versions" | awk -v installed="$installed_version_full" '
{
if ($0 == installed) {
print NR;
exit
}
}')
# Determine the alpha version status message
if [ -z "$installed_index" ]; then
echo "ERROR" "Installed version not found in available alpha versions."
alpha_version_message="Installed alpha version not found."
else
log "DEBUG" "Installed version found at index $installed_index"
alpha_updates_behind=$((installed_index - 1))
alpha_version_message="$alpha_updates_behind update(s) behind latest Alpha version $latest_alpha_version."
fi
}
# Function to fetch the latest regular version
fetch_regular_version() {
log "INFO" "Fetching latest regular version..."
regular_versions=$(curl -s https://updates.folivora.ai/bettertouchtool_release_notes.html | grep -Eo 'BetterTouchTool >= [0-9]+\.[0-9]+' | sed -E 's/BetterTouchTool >= //g' | sort -V)
latest_regular_version=$(echo "$regular_versions" | tail -n 1)
log "INFO" "Latest regular version: $latest_regular_version"
}
# Function to determine regular version status
determine_regular_status() {
# Compare the installed version with the latest regular version
comparison_result=$(version_compare "$installed_version_number" "$latest_regular_version")
# Determine the regular version status message
if [ "$comparison_result" -eq 0 ]; then
regular_version_message="Up to date with latest Regular version $latest_regular_version."
elif [ "$comparison_result" -eq 1 ]; then
regular_version_message="Installed version is ahead of latest Regular version $latest_regular_version."
else
regular_version_message="Installed version is behind latest Regular version $latest_regular_version."
fi
log "INFO" "$regular_version_message"
}
# Function to retrieve system information
get_system_info() {
device_info="$(/usr/libexec/PlistBuddy -c 'Print :0:product-name' /dev/stdin <<< "$(ioreg -arc IOPlatformDevice -k product-name)")"
macos_version="$(sw_vers -productVersion) ($(sw_vers -buildVersion))"
}
# Function to generate output
generate_output() {
if [ "$output_format" == "markdown" ]; then
# Markdown format
output_content=$(cat << EOF
- **Device**: $device_info
- **macOS**: $macos_version
- **BTT Version**: $installed_version_full
- **Alpha**: $alpha_version_message
- **Regular**: $regular_version_message
EOF
)
elif [ "$output_format" == "plain" ]; then
# Plain text format
output_content=$(cat << EOF
Device: $device_info
macOS: $macos_version
BTT Version: $installed_version_full
Alpha: $alpha_version_message
Regular: $regular_version_message
EOF
)
elif [ "$output_format" == "json" ]; then
# JSON format
# Use printf with double quotes and escape inner double quotes
output_content=$(printf "{\n \"Device\": \"%s\",\n \"macOS\": \"%s\",\n \"BTT_Version\": \"%s\",\n \"Alpha\": \"%s\",\n \"Regular\": \"%s\"\n}" \
"$device_info" \
"$macos_version" \
"$installed_version_full" \
"$alpha_version_message" \
"$regular_version_message")
else
echo "ERROR" "Unsupported output format: $output_format"
exit 1
fi
# Output the result
echo "$output_content"
# Copy to clipboard if enabled
if [ "$copy_to_clipboard" = true ]; then
echo "$output_content" | pbcopy
log "INFO" "Output copied to clipboard."
fi
}
# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
case $1 in
-v|--installed-version)
installed_version="$2"
shift 2
;;
-b|--installed-build)
installed_build="$2"
shift 2
;;
-l|--log-level)
log_level="$2"
shift 2
;;
-o|--output-format)
output_format="$2"
shift 2
;;
-c|--copy)
copy_to_clipboard=true
shift
;;
-n|--no-copy)
copy_to_clipboard=false
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown parameter passed: $1"
usage
;;
esac
done
# Validate log level
case "$log_level" in
NONE|ERROR|INFO|DEBUG)
# Valid log level
;;
*)
echo "Invalid log level: $log_level"
usage
;;
esac
# Validate output format
case "$output_format" in
markdown|plain|json)
# Valid output format
;;
*)
echo "Invalid output format: $output_format"
usage
;;
esac
# Check for required utilities and log their paths
check_requirements
# Main script execution
get_installed_version
fetch_alpha_versions
determine_alpha_status
fetch_regular_version
determine_regular_status
get_system_info
generate_output
Link to preset: BetterTouchTool Preset Sharing Platform