Search code examples
arraysslicefish

Is there a better way to get a possibly-empty array slice/range from some index to the end?


In fish array ranges are one-based and inclusive of both extremes, which, unsurprisingly, leads to problems when possibly-zero-length-ranges are required.

In particular, I'm in a situation where I split out the first arguments for my own consumption, and I want to forward the rest of them - which may be none! - to some command. If this was Python, I could do something like:

my_arg = sys.argv[1]
other_args = sys.argv[2:]

However, the straight translation of this to fish unfortunately doesn't work in edge cases; consider

set -l my_arg $argv[1]
set -l other_args $argv[2..-1]

(I kept the same indexes as, while in fish indexing is 1-based, $argv doesn't include what would be sys.argv[0])

This works fine as long as there are enough arguments; for example, if I invoke my command with arguments a b c d e I'll get $my_arg = a and $other_args = b c d e.

However, if I invoke it with just a, other_args will be surprisingly set to a as well. This comes from the fact that -1 actually gets expanded to something to the effect of (count $argv), so the statement above is equivalent to

set -l other_args $argv[2..1]

which is an inverted range from the nonexistent element 2 to the existent element 1, inclusive, which boils down to plain $argv[1].

To avoid this problem, currently I'm using this horrible workaround

set -l other_args $argv[2..(expr (count $argv) + 1)]

which ensures that the last index is one past the last, forcing the range to be a "straight" one, albeit possibly fully out of range (which returns an empty list as required).

However, I'm wondering: is there a better solution that I'm missing?


Solution

  • However, I'm wondering: is there a better solution that I'm missing?

    Upgrade to 3.0. This was a bug in 2.7 that is fixed there.

    The way this works now is that, if only one of the indices in a range is negative, it'll always be interpreted as the larger of the two, so with a negative end, iteration is forced to go forward.

    If the index isn't actually larger, this results in no elements instead, which is precisely what you want here.