Benjamin Sago / ogham / cairnrefinery / etc…

Technical notes Use ‘sudo’ with aliases in fish

Something that’s slightly annoying on the command-line is that sudo only works with executable binaries, and cannot know about shell aliases.

I have a bunch of ls-related aliases, like these:

alias l  'exa'
alias ls 'exa'
alias ll 'exa --long --git --header'
alias la 'exa -a --long --git --header'

(As mentioned in Make fish start faster by avoiding alias, they are actually functions rather than aliases, but the effect is the same for both.)

I’ve been writing ll instead of ls -l for so long now that I instinctively try to use it with sudo as well. However, sudo has no idea that it exists, because it’s an alias, rather than a file in the $PATH it can execute. This means that whenever I try to run this command using sudo, instead of a long file listing, I see this:

sudo ll
sudo: ll: command not found

I deal with this by having a fish wrapper function that runs the output through a sub-fish if it’s a function.

The ‘sudo’ fish wrapper

I have this function defined, which is also called sudo:

functions/sudo.fish
function sudo -d "sudo wrapper that handles aliases"
    if functions -q -- $argv[1]
        set -l new_args (string join ' ' -- (string escape -- $argv))
        set argv fish -c "$new_args"
    end

    command sudo $argv
end

It works by testing if the command that sudo is going to run — the first argument — is a defined function or fish alias, and if it is, it runs a new temporary fish session through sudo instead. The command that gets run looks like this:

sudo fish -c 'll'

The fish that gets run under sudo reads my list of aliases before running the command, so when it tries to execute ll, it’ll run the contents of the alias with root privileges.

Some notes about how this is implemented:

  • The uses of the string built-in are there to properly escape spaces before the function arguments get handed to the temporary fish process. Because this process takes two arguments (‘-c’ and a line of shell script to run) we need to take care when combining multiple arguments into one single string.
  • We need to run the result though command to stop the wrapper function from recursing and calling itself.
  • Finally, we need the ‘--’ meta-argument before the calls to functions and string to stop arguments to the program being run under sudo being treated as arguments to the functions or string built-ins themselves.

The function above is an improved version of one given in an answer to this Stack Overflow question. That one has issues with arguments containing spaces; the function on this page has that issue fixed.