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!

2 Answers 2


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.

  • 1
    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, 2019 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-

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .