Skip to content

Instantly share code, notes, and snippets.

@Sv443
Created September 27, 2025 16:45
Show Gist options
  • Select an option

  • Save Sv443/16c7839ac163c2a4a6f996bb32a623e8 to your computer and use it in GitHub Desktop.

Select an option

Save Sv443/16c7839ac163c2a4a6f996bb32a623e8 to your computer and use it in GitHub Desktop.
Bash script to download an asset from the latest GitHub release of a private repo
#!/bin/bash
set -e
OWNER=""
REPO=""
FILE_PATTERN="" # example: "build-*.zip"
TOKEN="" # personal access token with permissions to read "Content"
# INCLUDE_PRERELEASE="true" # whether to include prereleases - remove the # to enable
echo "Fetching releases for ${OWNER}/${REPO}..."
if [ "$INCLUDE_PRERELEASE" = "true" ]; then
echo "Including prereleases..."
# get all releases and find the latest one (including prereleases)
RELEASE_JSON=$(curl -s -H "Authorization: token ${TOKEN}" \
"https://api.github.com/repos/${OWNER}/${REPO}/releases" | \
jq '.[0]' 2>/dev/null || echo "[]")
# fallback if jq is not available
if [ "$RELEASE_JSON" = "[]" ] || [ -z "$RELEASE_JSON" ]; then
RELEASE_JSON=$(curl -s -H "Authorization: token ${TOKEN}" \
"https://api.github.com/repos/${OWNER}/${REPO}/releases" | \
sed -n '2,/^ }/p' | sed '$d')
fi
else
# get latest stable release
RELEASE_JSON=$(curl -s -H "Authorization: token ${TOKEN}" \
"https://api.github.com/repos/${OWNER}/${REPO}/releases/latest")
fi
if echo "$RELEASE_JSON" | grep -q "Not Found"; then
echo "Error: Repository not found or no access. Check your token and repository path."
exit 1
fi
if [ "$RELEASE_JSON" = "[]" ] || [ -z "$RELEASE_JSON" ]; then
echo "Error: No releases found."
exit 1
fi
# extract release tag and prerelease status
TAG=$(echo "$RELEASE_JSON" | grep '"tag_name":' | head -1 | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
IS_PRERELEASE=$(echo "$RELEASE_JSON" | grep '"prerelease":' | head -1 | sed -E 's/.*"prerelease": ([^,]+).*/\1/')
echo "Latest release: $TAG"
if [ "$IS_PRERELEASE" = "true" ]; then
echo "Note: This is a prerelease"
fi
matches_pattern() {
local filename="$1"
local pattern="$2"
regex_pattern=$(echo "$pattern" | sed 's/\./\\./g' | sed 's/\*/.*/'g)
echo "$filename" | grep -E "^${regex_pattern}$" > /dev/null
}
# extract assets section and get name/url pairs
ASSETS_SECTION=$(echo "$RELEASE_JSON" | sed -n '/"assets": \[/,/\]/p')
# find matching files based on pattern
DOWNLOAD_URL=""
FILENAME=""
FOUND_MATCH=0
TEMP_NAMES=$(mktemp)
TEMP_URLS=$(mktemp)
# extract all asset names and URLs
echo "$ASSETS_SECTION" | grep '"name":' | sed -E 's/.*"name": "([^"]+)".*/\1/' > "$TEMP_NAMES"
echo "$ASSETS_SECTION" | grep '"url":' | sed -E 's/.*"url": "([^"]+)".*/\1/' > "$TEMP_URLS"
# find matching file
line_num=1
while IFS= read -r current_name; do
if matches_pattern "$current_name" "$FILE_PATTERN"; then
FILENAME="$current_name"
DOWNLOAD_URL=$(sed -n "${line_num}p" "$TEMP_URLS")
FOUND_MATCH=1
break
fi
line_num=$((line_num + 1))
done < "$TEMP_NAMES"
rm "$TEMP_NAMES" "$TEMP_URLS"
if [ $FOUND_MATCH -eq 0 ]; then
echo "Error: No file matching pattern '$FILE_PATTERN' found in latest release."
echo "Available files:"
echo "$ASSETS_SECTION" | grep '"name":' | sed -E 's/.*"name": "([^"]+)".*/ - \1/'
exit 1
fi
echo "Downloading: $FILENAME"
echo "From: $DOWNLOAD_URL"
curl -L -H "Authorization: token ${TOKEN}" \
-H "Accept: application/octet-stream" \
-o "$FILENAME" \
"$DOWNLOAD_URL"
echo "Download successful: $FILENAME"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment