Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

conditionally set local variable in fish

Tags:

fish

I have carefully read the fish shell documentation, and I am trying to figure out how to conditionally set a local variable in a fish function.

In other words, if you have a function and you want a local variable to be modified with if-then-else logic.

function foo
    set --local variable something
    if blah
        set --local variable something_else
    end
end

For instance, assume I have a trivial function that accepts a filename as an argument, and if the file extension is missing, I want to add it to the argument.

function frob
    set --local filename $argv[1]
    echo "Before: $filename"

    if not string match --regex --entire "\.fish" $filename
        set --local filename $filename.fish
    end

    echo "After: $filename"
end

The problem is that since local variables only have block scope, this does not work. Running that "frob" function just prints the same thing in both the "Before" and "After".

The only work-around I can think of is to use a temporary global variable, and just manually delete it at the end of the function.

Example:

function frob
    # Use global variable, and try to handle collisions
    if  set --query --global filename
        set --global filename_saved $filename
    end

    set --global filename $argv[1]
    echo "Before: $filename"

    if not string match --regex --entire "\.fish" $filename
        set --global filename $filename.fish
    end

    echo "After: $filename"

    # Restore old saved value
    if set --query --global filename_saved
        set --global filename $filename_saved
        set --erase --global filename_saved
    else
        set --global --erase filename
    end
end

There are a couple of issues with this method, however. First of all, I would want to check for possible collisions with a preexisting global variable, and save any existing value to be restored when my script exits.

Unfortunately, if my script ends unexpectedly due to an error, it is possible that the "cleanup" code will never be executed.

Am I missing some better way to approach this problem?

like image 505
m0j0 Avatar asked Mar 05 '23 22:03

m0j0


1 Answers

"local" is a bit of a misnomer. It's "block-scoped".

That means when you do

begin
   set -l foo
end

$foo is only defined in that block.

And something like

set -l foo
begin
    set -l foo
end

will create a second version of $foo inside that block, and return to the other once the block ends.

So, what you need to do is to define it outside of the block and then just change it inside:

set -l foo
begin
    set foo bar
end

i.e.

function frob
    set --local filename $argv[1]
    echo "Before: $filename"

    if not string match --regex --entire "\.fish" $filename
        set filename $filename.fish
    end

    echo "After: $filename"
end
like image 68
faho Avatar answered Apr 12 '23 05:04

faho