Skip to content

Instantly share code, notes, and snippets.

@thesmart
Created February 4, 2026 01:56
Show Gist options
  • Select an option

  • Save thesmart/34051b233e1bfed5ae27bd4dbfd6b2c0 to your computer and use it in GitHub Desktop.

Select an option

Save thesmart/34051b233e1bfed5ae27bd4dbfd6b2c0 to your computer and use it in GitHub Desktop.
Installs a Go release tarball (e.g. go1.25.6.linux-amd64.tar.gz) in the `~/.local` folder following the XDG specification for user apps.
#!/bin/bash
#
# Installs a Go tarball to ~/.local/share/go/<version> and symlinks binaries to ~/.local/bin
#
# Usage: ./install-go.sh [options] <go-tarball>
# Example: ./install-go.sh go1.24.2.linux-amd64.tar.gz
set -euo pipefail
GO_BASE_DIR="$HOME/.local/share/go"
BIN_DIR="$HOME/.local/bin"
FORCE=false
# Print error message and exit
die() {
echo "Error: $1" >&2
exit 1
}
# Print help message
show_help() {
cat <<EOF
Usage: $0 [options] <go-tarball>
Installs a Go tarball to ~/.local/share/go/<version> and symlinks binaries
to ~/.local/bin.
Arguments:
<go-tarball> Path to a Go release tarball (e.g., go1.24.2.linux-amd64.tar.gz)
Options:
-h, --help Show this help message and exit
-f, --force Remove existing installation of the same version before installing.
Without this flag, the script will exit with an error if the
version is already installed.
Examples:
$0 go1.24.2.linux-amd64.tar.gz
$0 --force go1.24.2.linux-amd64.tar.gz
EOF
exit 0
}
# Print usage and exit
usage() {
echo "Usage: $0 [options] <go-tarball>"
echo ""
echo "Options:"
echo " -h, --help Show help message"
echo " -f, --force Remove existing version before installing"
echo ""
echo "Example: $0 go1.24.2.linux-amd64.tar.gz"
exit 1
}
# Extract version from tarball filename (e.g., "go1.24.2.linux-amd64.tar.gz" -> "1.24.2")
extract_version() {
local filename="$1"
local basename
basename=$(basename "$filename")
if [[ "$basename" =~ ^go([0-9]+\.[0-9]+(\.[0-9]+)?)\. ]]; then
echo "${BASH_REMATCH[1]}"
else
die "Could not extract version from filename: $basename"
fi
}
# Main
main() {
local tarball=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
show_help
;;
-f|--force)
FORCE=true
shift
;;
-*)
die "Unknown option: $1. Use --help for usage information."
;;
*)
if [[ -n "$tarball" ]]; then
die "Multiple tarballs specified. Use --help for usage information."
fi
tarball="$1"
shift
;;
esac
done
if [[ -z "$tarball" ]]; then
usage
fi
# Validate tarball exists and is readable
if [[ ! -f "$tarball" ]]; then
die "File not found: $tarball"
fi
if [[ ! -r "$tarball" ]]; then
die "File not readable: $tarball"
fi
# Validate it's a gzipped tar
if [[ "$tarball" != *.tar.gz && "$tarball" != *.tgz ]]; then
die "Expected a .tar.gz or .tgz file, got: $tarball"
fi
# Extract version
local version
version=$(extract_version "$tarball")
echo "Detected Go version: $version"
local install_dir="$GO_BASE_DIR/$version"
# Check if version already installed
if [[ -d "$install_dir" ]]; then
if [[ "$FORCE" == true ]]; then
echo "Removing existing installation at $install_dir..."
rm -rf "$install_dir"
else
die "Version $version already installed at $install_dir. Use --force to reinstall."
fi
fi
# Create directories
echo "Creating directories..."
mkdir -p "$GO_BASE_DIR"
mkdir -p "$BIN_DIR"
# Create temp directory for extraction
local tmpdir
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
# Extract tarball to temp directory
echo "Extracting $tarball..."
if ! tar -C "$tmpdir" -xzf "$tarball"; then
die "Failed to extract tarball"
fi
# Verify extraction produced a 'go' directory
if [[ ! -d "$tmpdir/go" ]]; then
die "Tarball did not contain expected 'go' directory"
fi
# Move to final location
echo "Installing to $install_dir..."
mv "$tmpdir/go" "$install_dir"
# Symlink binaries
echo "Creating symlinks in $BIN_DIR..."
local bin_path="$install_dir/bin"
if [[ ! -d "$bin_path" ]]; then
die "No bin directory found at $bin_path"
fi
for binary in "$bin_path"/*; do
if [[ -x "$binary" ]]; then
local name
name=$(basename "$binary")
local link="$BIN_DIR/$name"
if [[ -e "$link" || -L "$link" ]]; then
echo " Replacing existing: $name"
rm -f "$link"
else
echo " Linking: $name"
fi
ln -s "$binary" "$link"
fi
done
echo ""
echo "Go $version installed successfully!"
echo ""
echo "Make sure $BIN_DIR is in your PATH. Add to ~/.bashrc if needed:"
echo " export PATH=\"\$HOME/.local/bin:\$PATH\""
echo ""
echo "Verify with: go version"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment