1

I aliased sudo to please with a space:

$ alias please='sudo '
$ please ll

I have tried this in Fish, but it doesn't work:

$ alias please='sudo '
$ please ll
sudo: ll: command not found
NotTheDr01ds
  • 17,888
Octopus
  • 53
  • 7
  • "Aliases" in fish are actually functions, abbreviations are closer to aliases in bash. I don't think this behaviour is possible for either, though. You might make binding instead, but those are awkward too. – muru Apr 22 '22 at 17:28
  • @muru Right - It would be nice if either abbreviations or aliases/functions worked for the sudo case, but (a) aliases are tied to the user config, and (b) we'll need global abbreviations (not yet implemented) for it to work with abbr. – NotTheDr01ds Apr 22 '22 at 18:37

1 Answers1

3

The problem here isn't nested aliases. That in itself will work, although (as @muru points out in the comments) somewhat differently than Bash. For instance:

$ alias a ls
$ alias b type
$ b a
a is a function with definition
# Defined via `source`
function a --wraps=ls --description 'alias a ls'
  ls $argv; 
end

The problem with sudo in a Fish alias is twofold:

  • First, an alias is defined for your user, but when you sudo, you aren't "your user" any more. The fish configuration inside sudo is that of the root user. Unfortunately, the elegant Bash solution of appending a "space" doesn't work for Fish.

  • The Bash "trailing space" workaround of expanding the second alias before passing it to the first, via alias please='sudo ' isn't available in Fish. For instance, in the preceding example, in Bash you could use alias b='type ' to force expansion of a to ls and run the type command on the result rather than the alias.

    This is, IMHO, definitely one area where Bash has a (much) cleaner solution than Fish.

There are a few possible workarounds for Fish, but I think they are all rather "hacky", even my own.

First, as I mention in [this Stack Overflow answer], you can define your sudo alias as follows:

function please --wraps=sudo --description 'alias please sudo'
    if functions -q -- "$argv[1]"
        set cmdline (
            for arg in $argv
                printf "\"%s\" " $arg
            end
        )
        set -x function_src (string join "\n" (string escape --style=var (functions "$argv[1]")))
        set argv fish -c 'string unescape --style=var (string split "\n" $function_src) | source; '$cmdline
        command sudo -E $argv
    else
        command sudo $argv
    end
end

It would probably take me a bit to remember exactly how I arrived at that, which is why I left a commented version with the explanation here.

While you might consider defining the alias in the root user's Fish config, note that sudo only runs external commands, so it still won't run aliases this way, unless you ask a new fish process to run it. E.g.:

$ sudo -s
$ alias -s ll "ls -l"
funcsave: wrote /root/.config/fish/functions/ll.fish
$ exit # back to normal user
$ sudo fish -c "ll"
$ sudo ll
sudo: ll: command not found
$ sudo fish -c "ll -n /"
total 1436
lrwxrwxrwx   1 0 0       7 Apr 23  2020 bin -> usr/bin
drwxr-xr-x   2 0 0    4096 Apr 23  2020 boot
...
NotTheDr01ds
  • 17,888
  • Interesting, and the please function here might be what OP needs. But the initial example I think isn't quite what's expected. If I were expecting the bash behaviour, taking alias a='ls ' alias b='type ', the output should be ls is /usr/bin/ls. The behaviour you show would be that of alias b=type, for which bash would say a is aliased to `ls ', like fish here says a is a function.... – muru Apr 22 '22 at 21:45
  • @muru Great point - Edited to try to clarify that. Thanks! – NotTheDr01ds Apr 23 '22 at 00:40