11

I would like to use the abbreviations feature of the fish shell, especially for the known bash variable !! or aliases to common git commands. I know that abbreviations can be added like in the following snippet:

abbr -a gco git checkout

I also know that this setting is persisted in a file located at .config/fish/fishd.host, but this file is also saying that it should not be edited, since changes might be lost (because the file is auto generated).

So my question is how to add this abbreviations in a config file, because I want to put my dotfiles in a git repository. And if I use these dotfiles on a separate machine I don't want to execute all these abbr command again.

2
  • Did you ever find a good way to do this? I agree that the answer below isn't so useful.
    – ezuk
    Commented Apr 3, 2016 at 6:02
  • No, I didn't yet :-/ Commented Apr 5, 2016 at 7:37

7 Answers 7

14

Sorry, I'm not sure if I understand what you're asking. But if your question is how to set your abbr definitions on startup (and in a file that you can store in a repository and share between machines), you should use the file ~/.config/fish/config.fish which is Fish's equivalent to .bashrc in Bash.

Since abbreviations are stored in global/universal variables, they don't need to be reset every time you open a terminal window, so you can place a safeguard in that config file to prevent resetting them every time (speeding things up a bit), as explained here: https://github.com/fish-shell/fish-shell/issues/1976#issuecomment-168698602

Edit (April 2019):

After Fish changed the way universal variables are stored in version 3.0.0 the safeguard functionality seems to prevent changes made in the abbr list to be included also after opening new terminal windows or rebooting one's machine. So, I've removed those lines from the example.

E.g. my config.fish looks like this (for Git commands):

  echo -n Setting abbreviations... 

  abbr g 'git'
  abbr ga 'git add'
  abbr gb 'git branch'
  abbr gbl 'git blame'
  abbr gc 'git commit -m'
  abbr gca 'git commit --amend -m'
  abbr gco 'git checkout'
  abbr gcp 'git cherry-pick'
  abbr gd 'git diff'
  abbr gf 'git fetch'
  abbr gl 'git log'
  abbr gm 'git merge'
  abbr gp 'git push'
  abbr gpf 'git push --force-with-lease'
  abbr gpl 'git pull'
  abbr gr 'git remote'
  abbr grb 'git rebase'
  abbr gs 'git status'
  abbr gst 'git stash'

  echo 'Done'
1
  • 1
    Thanks for this, reading the docs (fishshell.com/docs/current/commands.html) below the first snippet of code, the paragraph is really vague about it and only says it will "slow down the shell" but does not offer this incredibly simple alternative alongside it, cheers again!
    – SidOfc
    Commented Feb 7, 2018 at 20:34
3

The canonical Fish way to initialize universal abbreviations would be to be to create an abbr.fish file in your ~/.config/fish/conf.d that does the initialization. In that file you check a universal variable for whether your abbreviations have been set yet. This will set them and the indicator variable once, ensuring that you don't incur the cost on every shell invocation.

# ~/.config/fish/conf.d/abbr.fish
if not set -q MY_ABBR_SET
    set -U MY_ABBR_SET true

    abbr -a -- - 'cd -'
    abbr -a la 'ls -la'
    abbr -a ldot 'ls -ld .*'
    abbr -a ll 'ls -lGFh'
    abbr -a lsa 'ls -aGF'
    abbr -a nv nvim
    abbr -a tarls 'tar -tvf'
    abbr -a untar 'tar -xv'
    abbr -a zz exit

    # git
    abbr -a gad 'git add'
    abbr -a gbn 'git rev-parse --abbrev-ref HEAD'
    abbr -a gcl 'git clean'
    abbr -a gco 'git checkout'
    abbr -a gwhoami 'echo "user.name:" (git config user.name) && echo "user.email:" (git config user.email)'
    # ... etc...
end

If you want to change or add new abbreviations, simply modify the abbr.fish file and then erase the variable. On the next fish invocation, your abbreviations will be set up again:

# erasing this will cause abbr.fish
# to setup your abbreviations again
set -e MY_ABBR_SET

If you need to clear out all your abbreviations and start over, this function can help:

function abbr-erase-all --description 'Erase all your abbrs'
    while true
        read -l -P "This will erase all your abbreviations. You sure? [y/N] " confirm
        switch $confirm
            case Y y
                break
            case '' N n
                return 1
        end
    end
    for abbr_name in (abbr -l)
        abbr -e $abbr_name
    end
    set -q MY_ABBR_SET && set -e MY_ABBR_SET
end
3
  • What is the point of the check is set variable? When will this file be run when the variables are already set?
    – Jonathon
    Commented Jun 5, 2022 at 21:33
  • It's merely a speed optimization. No need to redefine your universals every time you invoke a new shell unless you're actively changing things. If you don't like that convention, you don't have to use it. I prefer my shell to be blazing fast.
    – mattmc3
    Commented Nov 1, 2022 at 18:58
  • 1
    This is no longer functional as of fish 3.6.0 as abbreviations are no longer universal.
    – anothermh
    Commented Jan 25, 2023 at 22:15
2

Fixed this! What I ended up doing is just making the output of abbr -s into a Fish script. So in brief:

abbr -s > abbr.fish
(edit abbr.fish, add the following line to the top:) #! /usr/bin/fish
chmod +x abbr.fish

And you're done!

All you have to do now is just run abbr.fish on any Fish machine you want your abbreviations on, and presto.

0

Abbreviations are stored as universal variables in fish, so, in my opinion, they are more suitable to be used interactively as a quick & dirty™ way to persist your favorite expansions.

If you would like this configuration to be available in other boxes and sync them up with your dotfiles, I recommend creating a function as gco.fish, etc., for each abbreviation instead.

  • gco.fish

    function gco
        command git checkout $argv
    end
    

Functions are lazily loaded in fish and will always perform better than running abbr (which is also not a fish builtin, but a regular function with a definition type abbr) for each abbreviation in your config.fish.

5
  • 1
    But this way the aliases won't auto expand as if they were abbreviations, or do they? That's like the coolest thing about the abbreviations ;-) Commented Mar 8, 2016 at 6:56
  • Yes, you are correct. It's a small tradeoff. I personally don't use abbr as they are implemented using universal variables and those, while super handy, it's something I will avoid if I can.
    – j--
    Commented Mar 8, 2016 at 10:23
  • 3
    Another disadvantage is that auto complete doesn't work for me anymore... Typing gco <tab> doesn't show the branches anymore... Commented Mar 8, 2016 at 21:03
  • @DanielRotter It would be too good if the function could inherit completions automatically. But the good news is, it would not be hard at all to use complete to copy the existing git completions into each of the functions. You will need a directory for your "git aliases", a functions directory for each function and a completions directory to add your completions, ideally one for each function too, but not necessarily so.
    – j--
    Commented Mar 9, 2016 at 2:15
  • It is an answer, though I must say I wouldn't opt for this either due to aforementioned comments (e.g. breaking things that you'd use abbreviations for). Also, using complete isn't something most users setting up a shell want to be bothered with. It's not all that trivial, requires reading up on (not all that clear IMO) docs and learning the programs you wish to "polyfill" the completions for (to some deeper extent than you might imagine at first). Also, what about updates? Won't be fun keeping all your custom completions up-to-date either :)
    – SidOfc
    Commented Jun 5, 2019 at 8:51
0

I have been trying fish again, and found a solution which is working for me now. It is also described that way in the fish documentation.

They simply suggest to reset fish_user_abbreviations and call every abbr again and again. (I didn't even use the if in my case, also works well)

if status --is-interactive
    set -g fish_user_abbreviations
    abbr --add first 'echo my first abbreviation'
    abbr --add second 'echo my second abbreviation'
    # etcetera
end

It's actually similar to what MJV suggested, but without the downside that it is cached. The tradeoff is probably that startup is a little bit slower, but I'll keep an eye on that. I am going with that variant, since it is also mentioned in the documentation.

0

The abbr command now has a -g/--global option to store the abbreviations globally (within the current shell) instead of universally, so you can add the abbr commands to your config.fish:

abbr --global --add ga 'git add'
...
0

To restore the pre-3.6.0 functionality of abbr you can use this command:

echo source '$__fish_config_dir/abbreviations' >> ~/.config/fish/config.fish

function abbrsave
    echo abbr -a -U -- $argv[1] (string join -- ' ' (string escape -- $argv[2..-1])) >> ~/.config/fish/abbreviations 
end

funcsave abbrsave

abbrsave ps ps -o etime,stat,command ww

Then ps will expand in new shells

But if you want to edit or remove the abbreviation you'll need to edit the file: ~/.config/fish/abbreviations

Or use a more hacky solution like this (requires moreutils):

function filterfile --argument file word
    if test -n "$word"
        grep -i "$word" "$file"
        grep -iv "$word" "$file" | sponge "$file"
    end
end
funcsave filterfile

function abbrsave
    abbr -a -U -- $argv[1] (string escape -- $argv[2..-1])

    filterfile ~/.config/fish/abbreviations "abbr -a -U -- $argv[1]"
    echo abbr -a -U -- $argv[1] (string escape -- $argv[2..-1]) >> ~/.config/fish/abbreviations
end
funcsave abbrsave

This will print the previous definition of the abbr when you overwrite it with something new.

But for a more dynamic abbreviations I would follow the manual's advice and just write those directly into config.fish:

function _abbr_zip
    echo zip -qr (datestamp).zip
end
abbr -a zip --function _abbr_zip

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .