Using jq
is always the best option to parse JSON data:
#!/usr/bin/env bash
for i in {1..10}
do
curl \
--user USERNAME:PASS \
--silent \
"https://api.github.com/user/repos?page=${i}" \
| jq \
--raw-output '.[] | "git clone \(.clone_url)"' \
> "output${i}.txt"
done
Or to handle an arbitrary number of pages, you can tell jq
to return a non-null return-code in $?
by providing it with the --exit-status
option.
Then if the JSON selector returns no result (witch happens when the returned GitHub API's result page is empty) the jq
return-code can be tested to continue or terminate the while loop:
#!/usr/bin/env bash
typeset -i page=1 # GitHub API paging starts at page 1
while clone_cmds="$(
curl \
--user USERNAME:PASS \
--silent \
"https://api.github.com/user/repos?page=${page}" \
| jq \
--exit-status \
--raw-output \
'.[] | "git clone \(.clone_url)"'
)"; do
# The queried page result length is > 0
# Output to the paged file
# and increase page number
echo >"output$((page++)).txt" "${clone_cmds}"
done
If you want the same as above but all repositories in a single file.
The following example feature GitHub API handling of pages, rather than relying on an extra empty request to mark the end of the pages.
It now also handles pages of up to 100 entries, and negotiate a compressed transport stream if supported.
Here is the featured version of your repository cloning list:
#!/usr/bin/env bash
# Set either one to authenticate with the GitHub API.
# GitHub 'Oauth2 token':
OAUTH_TOKEN=''
# GitHub 'username:password':
USER_PASS=''
# The GitHub API Base URL:
typeset -r GITHUB_API='https://api.github.com'
# The array of Curl options to authenticate with GitHub:
typeset -a curl_auth
# Populates the authentication options from what is available.
if [[ -n ${OAUTH_TOKEN} ]]; then
curl_auth=(--header "Authorization: token ${OAUTH_TOKEN}")
elif [[ -n ${USER_PASS} ]]; then
curl_auth=(--user "${USER_PASS}")
else
# These $"string" are bash --dump-po-strings ready.
printf >&2 $"GitHub API need an authentication with either set variable:"$'\n'
printf >&2 "OAUTH_TOKEN='%s'\\n" $"GitHub API's Oauth2 token"
printf >&2 $"or"" USER_PASS='%s:%s'.\\n" $"username" $"password"
printf >&2 $"See: %s"$'\n' 'https://developer.github.com/v3/#authentication'
exit 1
fi
# Query the GitHub API for user repositories.
# The default results count per page is 30.
# It can be raised up to 100, to limit the number
# of requests needed to retrieve all the results.
# Response headers contains a Link: <url>; rel="next" as
# long as there is a next page.
# See: https://developer.github.com/v3/#pagination
# Compose the API URL for the first page.
next_page_url="${GITHUB_API}/user/repos?per_page=100&page=1"
# While there is a next page URL to query...
while [[ -n ${next_page_url} ]]; do
# Send the API request with curl, and get back a complete
# http_response witch --include response headers, and
# if supported, handle a --compressed data stream,
# keeping stderr &2 --silent.
http_response="$(
curl \
--silent \
--include \
--compressed \
"${curl_auth[@]}" \
"${next_page_url}"
)"
# Get the next page URL from the Link: header.
# Reaching the last page, causes the next_page_url
# variable to be empty.
next_page_url="$(
sed \
--silent \
'/^[[:space:]]*$/,$d;s/Link:.*<\(.*\)>;[[:space:]]*rel="next".*$/\1/p' \
<<<"${http_response}"
)"
# Get the http_body part from the http_response.
http_body="$(sed '1,/^[[:space:]]*$/d' <<<"${http_response}")"
# Query the http_body JSON content with jq.
jq --raw-output '.[] | "git clone \(.clone_url)"' <<<"${http_body}"
done >"output.txt" # Redirect the whole while loop output to the file.