Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to abort a fish script from a lower-level function?

Given a fish script foo.fish that only prints "foo", help, or an error

function foo
  __parse_args $argv[1]
  echo foo
end

function __parse_args --argument option
  if test -z $option
    return  # No option to parse, return early
  end

  switch $option
    case -h --help
      echo "Shows this help and exits"
      return 0  # How can we exit 0 instead of return?
    case -\*
      echo "Error: '$option' not a valid option"
      return 1  # How can we exit 1 instead of return?
  end
end

Actual behaviour:

↪ foo -h
Shows this help and exits
foo

Expected behaviour:

↪ foo -h
Shows this help and exits

The return manual says it stops the current inner function and sets the exit status of the function.

How can we exit the script early when inside nested function calls, with the appropriate exit code?

Note we cannot use exit because it will exit the shell instead of just the script.

like image 355
Dennis Avatar asked Jun 11 '17 13:06

Dennis


1 Answers

Unless you run the script via source or .,it is run in its own new shell process. The exit command will terminate that process and return to the parent shell that invoked the script; the parameter to exit will be the value of $status inside that parent process immediately after the exit.

If you are actually defining the foo function in your interactive shell (via source or . or typing/pasting at your shell prompt or by defining it in your .fishrc or a startup file in ~/.config or whatever) then there is no way for __parse_args to return from foo. foo will have to check the return value of __parse_args (that is, check $status after calling __parse_args) explicitly and then return immediately if appropriate. That also means that it's up to __parse_args to return a different value when processing --help than when otherwise successful.

However, unless the actual operation of foo involves some modification to your shell environment, I would recommend making it an executable script file instead of a function, for example by putting this into a file named foo somewhere in your command search $PATH:

#!/usr/bin/env fish
function foo
  __parse_args $argv[1]
  echo foo
end

function __parse_args --argument option
  if test -z $option
    return  # No option to parse, return early
  end

  switch $option
    case -h --help
      echo "Shows this help and exits"
      exit 0  # How can we exit 0 instead of return?
    case -\*
      echo "Error: '$option' not a valid option"
      exit 1  # How can we exit 1 instead of return?
  end
end

foo $argv

That has the desired result:

> foo
foo
> foo -x
Error: '-x' not a valid option
[1]> foo -h
Shows this help and exits
>
like image 180
Mark Reed Avatar answered Oct 31 '22 22:10

Mark Reed