Search code examples
fish

Can function get empty arguments?


My code

function foo
    argparse -n foo 'u/user=' 'g/group=' 's/shell=' -- $argv

    bar $_flag_u $_flag_g $_flag_s
end

function bar -a user group shell
    echo $user
    echo $group
    echo $shell
end

foo $argv

Execute and Result

> fish test.fish -u user_name -g group_name -s shell_name
user_name
group_name
shell_name
> fish test.fish -g group_name -s shell_name
group_name
shell_name

> fish test.fish -u user_name -s shell_name
user_name
shell_name

>

Expectation I want

> fish test.fish -u user_name -g group_name -s shell_name
user_name
group_name
shell_name
> fish test.fish -g group_name -s shell_name

group_name
shell_name
> fish test.fish -u user_name -s shell_name
user_name

shell_name
>

Can I get the expectation?
If -u option is not used, my expectation is that $user in bar function is empty.
(it means that result of "echo $status" is 1 after "set -q user".)

If I have no choice, I'll do bellow:
(Reference: https://github.com/fish-shell/fish-shell/issues/3926)

function foo
    argparse -n foo 'u/user=' 'g/group=' 's/shell=' -- $argv

    set -q _flag_u; or set _flag_u ''
    set -q _flag_g; or set _flag_g ''
    set -q _flag_s; or set _flag_s ''

    bar $_flag_u $_flag_g $_flag_s
end

function bar -a user group shell

    if test -n $user
        # do something
    end
    if test -n $group
        # do something
    end
    if test -n $shell
        # do something
    end
end

foo $argv

Solution

  • Your issue is this:

    function bar -a user group shell
    

    This means bar calls its first argument "user", the second "group" and the third "shell".

    When you then run

    bar $u $g $s
    

    fish expands the variables. If they are set, they'll expand to as many arguments as they have elements (in fish, all variables are lists!).

    So you'll get $u into $user, $g into $group and $s into $shell.

    However, if one isn't set (because the option wasn't given in the call to foo), then the variable will expand to nothing, so if e.g. --group wasn't given, this works like

    bar $u $s
    

    which will assign the contents of $u to $user and $s to $group - because it is the second argument that bar sees.

    To inhibit this, either use set -q or double-quote the variable:

        bar "$_flag_u" "$_flag_g" "$_flag_s"