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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.