0

I am trying to make a small shell script function where basically it should return me only the two latest versions of a github repository (not counting the latest). Here is my code:

get_release() {
curl --silent \
  -H "Accept: application/vnd.github.v3+json" \
  https://api.github.com/repos/user/repo/releases |
  grep '"tag_name":' |
  sed -E 's/.*"([^"]+)".*/\1/' 
}

#str="1.1.1 2.2.2 3.3.3 4.4.4 5.5.5 6.6.6 7.7.7 8.8.8 9.9.9"
str=($get_release)

#VERSION=$(get_release)
IFS=', ' read -r -a array <<< "$str"

LASTVERSION=${array[-2]}
PENULTIMATEVERSION=${array[-3]}

echo "${LASTVERSION}"
echo "${PENULTIMATEVERSION}"

But I'm getting this when I try to run:

t.sh: line 17: array: bad array subscript
t.sh: line 18: array: bad array subscript

Note: the commented str variable is just a simulation of an array, with it working normally, but when trying to use the get_release function, I get this error.

11
  • 1
    You'll get that error if there aren't enough values in the array. What does declare -p str array show? Commented Apr 5, 2022 at 22:36
  • 4
    Try str=($(get_release)) Commented Apr 5, 2022 at 22:46
  • declare -p str array return this: t.sh: line 23: declare: v2.2.4: not found t.sh: line 23: declare: v2.2.3: not found t.sh: line 23: declare: v2.2.2: not found t.sh: line 23: declare: v2.2.1: not found t.sh: line 23: declare: v2.2.0: not found t.sh: line 23: declare: v2.1.0: not found t.sh: line 23: declare: v2.0.0: not found Commented Apr 5, 2022 at 23:14
  • @Philippe str=($(get_release)) It had no effect, same error. Commented Apr 5, 2022 at 23:16
  • 1
    @Philippe, please don't encourage people to populate arrays with string splitting. It has unintended side effects such as glob expansion -- the read -r -a approach is the Right Thing. Commented Apr 5, 2022 at 23:29

3 Answers 3

1

As a working example which is compatible with all bash releases from 3.2 forward:

get_releases() {
  local user=$1 repo=$2
  curl --silent \
    -H "Accept: application/vnd.github.v3+json" \
    "https://api.github.com/repos/$user/$repo/releases" |
    jq -r '.[].tag_name'
}

IFS=$'\n' read -r -d '' -a releases < <(get_releases juji-io datalevin && printf '\0')
echo "Newest release: ${releases[0]}"
echo "Oldest release: ${releases[${#releases[@]}-1]}"
echo "Second oldest:  ${releases[${#releases[@]}-2]}"

...which as of present date correctly emits (for the juji-io/datalevin project used in the example above):

Newest release: 0.6.6
Oldest release: 0.5.13
Second oldest:  0.5.14
Sign up to request clarification or add additional context in comments.

Comments

0

As per @Philippe's comments ($get_release) will not call your function, but $(get_release) will.

As per @Charles Duffy and @glenn jackman's comments for I've updated the code snippet for safely checking and accessing the last elements of an array.

Here's the amended code snippet:

get_release() {
curl --silent \
  -H "Accept: application/vnd.github.v3+json" \
  https://api.github.com/repos/user/repo/releases |
  grep '"tag_name":' |
  sed -E 's/.*"([^"]+)".*/\1/' 
}

# str=($get_release) # Warning: this does not call get_release
# str='1.1.1 2.2.2 3.3.3 4.4.4 5.5.5 6.6.6 7.7.7 8.8.8 9.9.9'
str=$(get_release)

IFS=', ' read -r -a array <<< "$str"

n=${#array[@]}
((n > 1)) && LASTVERSION=${array[$((n-1))]}
((n > 2)) && PENULTIMATEVERSION=${array[$((n-2))]}

echo "${LASTVERSION}" # 9.9.9
echo "${PENULTIMATEVERSION}" # 8.8.8

Here's another solution based on perl, regex, and capture groups, i.e.

# str=($get_release) # Warning: this does not call get_release
# str='1.1.1 2.2.2 3.3.3 4.4.4 5.5.5 6.6.6 7.7.7 8.8.8 9.9.9'
str=$(get_release)
LASTVERSION=$(perl -ne 'print if s/.* (\d+\.\d+\.\d+)/\1/' <<< $str)
PENULTIMATEVERSION=$(perl -ne 'print if s/.* (\d+\.\d+\.\d+) \d+\.\d+\.\d+/\1/' <<< $str)

echo "${LASTVERSION}" # 9.9.9
echo "${PENULTIMATEVERSION}" # 8.8.8

7 Comments

I'm not sure this answers the whole of the question. The way the OP is indexing into their array is also broken.
(whether ${array[-2]} works to index backwards is very version-dependent; it's not a feature that has been around long enough to be relied on)
...also, set -e is... controversial, to put it kindly. See the exercises section of BashFAQ #105 illustrating some of the many gotchas it ropes in.
Thanks @CharlesDuffy looks like I have reading to do.
"not a feature that has been around long enough to be relied on" -- it was introduced in version 4.2, released in 2011. version 4.3 introduces setting and unsetting using a negative index.
|
0

Thanks to everyone who helped me, I was able to solve it this way:

get_release() {
curl --silent \
  -H "Accept: application/vnd.github.v3+json" \
  https://api.github.com/repos/user/repo/releases |
  grep '"tag_name":' |
  sed -E 's/.*"([^"]+)".*/\1/' 
}

CREATE_ARRAY=$'\n' read -d "\034" -r -a array <<< "$(get_branch)\034" # See: https://unix.stackexchange.com/questions/628527/split-string-on-newline-and-write-it-into-array-using-read

PENULTIMATE_VERSION="${array[2]}"
ANTIPENULTIMATE_VERSION="${array[1]}"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.