In zsh, if your versions are in lexicographic order:
rm -f appname_*.tar.gz(N[1,-$((n+1))])
The glob qualifier
[NUM1,NUM2] retains only the matches from NUM1 to NUM2. With a minus sign, the number counts from the end (-1 is the last match), so
[1,-$((n+1))] matches all but the last
$n files. The glob qualifier
N says that it's ok if there is no match (which happens if there are no more than
$n files already).
If the versions aren't in lexicographic order, you may need to sort the files in a different order. The glob qualifier
n sorts decimal numbers by value, so this will work correctly if you have
appname_9_somedate followed by
rm -f appname_*.tar.gz(nN[1,-$((n+1))])
If you have more complex version numbers, you can specify your own sort function. Write a zsh function
version_less that returns 0 if its first argument is less than its second argument, and use
rm -f appname_*.tar.gz(N[1,-$((n+1))]o+version_less)
In any shell, if the order of the files is lexicographic order, you can iterate through the matches.
while [ $# -gt $n ]; do
If you need a different order, parsing the output of
ls is your best bet. Note that
ls mangles non-printable characters in file names, but in your case that shouldn't be a problem.