I needed to script the install of the Digital Ocean CLI " doctl " tool from Github using curl, but there was a problem: The filename varied as it incorporated the version number- so hard-coding it would have required editing the script every time a new version was released, negating the entire point of automating it!

Just globbing with asterisks (or "stars" as some call them) in the path for variable directory & file names won't work.

The path I have to work with:


As you can see, even the directory the file lives in is variable by the version number.

I'll show the way I solved the problem, which might not be the most elegant solution. If you have a tidier one, please share it!


Do the curl -sL (to drop the progress bar and follow redirects), just like you were, but give it the URL for the latest linux-amd64 release:

curl -sL "$(curl -L -s https://api.github.com/repos/digitalocean/doctl/releases/latest |
  jq -r '.assets[] | select(.name | contains("-linux-amd64.tar.gz")).browser_download_url')" |
    tar -xzv

The inner command substitution asks the github API for the latest release of that repo; it then pipes it through jq to select the element whose name contains the string -linux-amd64.tar.gz and return back the download URL.

  • Your solution creates a circular dependency for RHEL users (which is most enterprise Linux users): in order to download the Digital Ocean " doctl " tool from Github, you must first download another Github tool: jq (not available in RHEL repos), which itself exists in an arbitrary, unpredictable path pointing to an S3 bucket than " doctl ". But this path cannot be inferred, making it unscriptable so the install of " doctl " now would have a manually step installing jq. If jq were in the default RHEL repo this would have been a great solution! – F1Linux Apr 15 at 7:50

I broke the path down into (3) parts:

  1. Non-Variable Base: The part of the path which is 100% predictable and will not be subject to future change


  1. Variable DIRECTORY Name: The name of the directory is the release number. So although it's variable, it still predictable because it uses Semantic Versioning (https://semver.org/):

v$(curl -s https://github.com/digitalocean/doctl/releases/ | grep -om 1 'doctl-.*-linux-amd64.tar.gz'|grep -Eo '[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}')/

The operation is to find the latest file and extract the version number from it. Since the " v " in the directory name is not part of the file name, it cannot be captured by a grep. So I've just hard-coded in front of the self-populating variable

  1. Variable FILE Name: The operation of the following expression extracts just the latest version (the " m 1 " part) file name:

$(curl -s https://github.com/digitalocean/doctl/releases/ | grep -om 1 'doctl-.*-linux-amd64.tar.gz')

The whole ugly thingy looks as follows (with a " | tar -xzv " tacked on the end):

curl -sL https://github.com/digitalocean/doctl/releases/download/v$(curl -s https://github.com/digitalocean/doctl/releases/ | grep -om 1 'doctl-.*-linux-amd64.tar.gz'|grep -Eo '[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}')/$(curl -s https://github.com/digitalocean/doctl/releases/ | grep -om 1 'doctl-.*-linux-amd64.tar.gz') | tar -xzv

This download will continue to succeed without any necessity to manually edit the script where the file & directory names change in future releases.

Again, might not be the most elegant solution, but solves the problem effectively. If you have a better approach, please share! HTH-

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.