Search code examples
shellscriptingfish

Changing Values of Lists In Loop With Fish Shell Script


I am trying to iterate over a fish shell list and change the values of the elements saving those new values into that list.

The original list is populated like this:

set -l dockApplications (ls $HOME/.config/plank/dock1/launchers/)

This works and produces a list like this:

emacsclient.dockitem firefox.dockitem monodevelop.dockitem Thunar.dockitem

Now I want to iterate over it and change the string "dockitem" to "desktop".

I have tried a for loop but I do not appear to be using it correctly:

for application in $dockApplications
     echo $application
     set application (string replace 'dockitem' 'desktop' $application )
     echo $application
     echo "==========="
end

This echos the before and after the string operation and I produce the correct string. but when I do something like echo $dockApplications after the for loop. I get the list of strings with the "dockitem" extension.

I have also tried setting the $dockApplications variable differently like:

set -l dockApplications (string replace 'dockitem' 'desktop' (ls $HOME/.config/plank/$dockdir/launchers/))

But that seems to return the same list of strings with the "dockitem" extension.

I think I am fundamentally misunderstanding either how variables are assigned or how the scope of them is handled here.

I have never fully wrapped my head around shell scripting. I can read it and get what is going on but when it comes to implementing it I hit a few road blocks when I try to achieve something in a way that I would in a different language. But I realize the power of shell scripting and would like to get better at it. So any pointers on how to do this in a fish shell idiomatic way are greatly appreciated.


Solution

  • I would iterate over the indices of the list so you can update in place:

    set apps (printf "%s\n" ./launchers/*.dockitem)
    for i in (seq (count $apps))
        set apps[$i] (string replace "dockitem" "desktop" $apps[$i])
    end
    printf "%s\n" $apps
    

    This also works without a loop:

    set apps (string replace dockitem desktop (printf "%s\n" ./launchers/*.dockitem))
    printf "%s\n" $apps
    

    If I recall, fish splits the output of a command substitution on newlines when saving to an array