51
my-fish-script a b c d

Say you want to get the all arguments from the second argument onwards, so b c d.

In bash you can use shift to dump the first argument and access the remaining ones with "$@".

How would you solve the problem using the fish shell?

Dennis
  • 56,821
  • 26
  • 143
  • 139

3 Answers3

83

In fish, your arguments are contained in the $argv list. Use list slicing to access a range of elements, e.g. $argv[2..-1] returns all arguments from the second to the last.

For example

function loop --description "loop <count> <command>"
  for i in (seq 1 $argv[1])
    eval $argv[2..-1]
  end
end

Usage

$ loop 3 echo hello world
hello world
hello world
hello world
Dennis
  • 56,821
  • 26
  • 143
  • 139
  • 3
    @AliGajani I did. It's a question I had that I couldn't find the answer to on SO, so I'm adding it now to help others. In fact, [SO encourages you to answer your own questions](http://stackoverflow.com/help/self-answer). – Dennis Jun 07 '14 at 04:36
  • welp the comment-ificition strips out all the whitespace making it unreadable... how are you supposed to... whatever, [here](https://gist.github.com/OwenAR/45b034152442951f3c34#file-gistfile1-txt). so you can't just use `set argv $argv[2..-1]` as a direct translation from bash, i mean. so i guess you're supposed to translate the logic to something different in "idiomatic fish"? unless there's some built-in function that actually has the same behavior? – Owen_AR Dec 29 '15 at 02:53
  • @Owen_R It's still not clear what you're asking. Are you wondering how to simulate the behaviour of `shift` in fish? If so, see [this answer](http://stackoverflow.com/a/24101186/72321). Otherwise this discussion is off topic and you would be better off [asking a new question](http://stackoverflow.com/questions/ask). – Dennis Dec 29 '15 at 13:12
  • 1
    and how do you get the `$0` argument (the script's name)? `status -f`? – xealits Oct 16 '16 at 03:17
  • 1
    @xealits see http://stackoverflow.com/questions/16975804/how-to-get-the-program-name-in-a-fish-shell-script – Dennis Oct 22 '16 at 17:36
  • 1
    keep in mind that indexes start at 1, i.e. `$argv[1]` – max pleaner Jan 19 '17 at 17:08
  • @maxpleaner thanks for the clarification , i was assuming thad indexes start at 0 and that was confusing me – Tarik Waleed Dec 06 '22 at 18:05
28

The behaviour of the shift command can be simulated with set -e/--erase VARIABLE_NAME.

The idea is to erase the first argument, then get the remaining arguments from the $argv list.

For example

function loop  --description "loop <count> <command>"
  set count $argv[1]
  set --erase argv[1]
  for i in (seq 1 $count)
    eval $argv
  end
end

Usage

$ loop 3 echo hello world
hello world
hello world
hello world
Dennis
  • 56,821
  • 26
  • 143
  • 139
  • 4
    If anyone is wondering, I [answered twice, because the answers are distinct](http://meta.stackexchange.com/a/25210/253951). This way the community can decide which answer is better and can easily comment on the different answers. – Dennis Jun 07 '14 at 20:20
  • I erase multiple times more like this method to potentially access remaining optional arguments more safely. I do not do any explicitly counting of the array. Nicely `set` does not fail on alternative 'accessing' a first indexed array argument. – Pysis Jun 27 '19 at 19:47
12

You could also use read which is more readable in my opinion:

function loop
  echo $argv | read -l count command
  for i in (seq 1 $count)
    eval $command
  end
end

This works better especially when you want to use more than the first argument.

echo $argv | read -l first second rest
terje
  • 4,164
  • 2
  • 28
  • 28
  • @readers, `... | read -l ...` performs pattern matching over it's input to set the given variable names. This won't work if the firsts argv value contain space -- not a risk here. – loxaxs Apr 20 '18 at 05:46