How do you set alias sudo='nocorrect sudo ' correctly?

The behavior is reproducible with:

alias sudo='nocorrect sudo '
alias mv='nocorrect mv '

So, when executing sudo mv foo bar this gets expanded to

nocorrect sudo nocorrect mv foo bar

and throws an error as nocorrect is a shell reserved word and cannot be handled by sudo.

The reason that the mv alias gets expanded is that you define alias sudo='nocorrect sudo ' with a trailing blank, which enables alias expansion afterwards. Without that trailing blank this example works, but you loose the capability to use aliases after sudo completely.

A workaround to have alias expansion generally after sudo, but to prevent the error with sudo mv escape the mv command when using it with sudo:

sudo \mv foo bar

This prevents the alias expansion of mv.


Ok, I've been digging into this for a while and have found some stuff on the zsh mailing list. There doesn't seem to be one "silver bullet" solution but a bunch of different solutions which do different things. I'm going to post what I've done (which is a bit of a cop out) but also explore the other approaches and their problems. I'm personally going to go with:

➜  ~  alias sudo='sudo '
➜  ~  alias nsudo='nocorrect sudo'

EDIT:

I am now going to go with

sudo \mv foo bar

for the cases where I need this as descibed by @mpy in the alternate answer.

/EDIT

because it will allow me to use aliases most of the time and when they complain because they're aliased to nocorrect I can use nsudo so that I don't accidentally clobber my files.

Better approaches are from the zsh mailing lists. There appears to be two threads that I've found on this. One from 1999 here (that's the question, see the follow ups, especially this one which solves the noglob problem. I am unsure if it solves nocorrect as well (does noglob imply nocorrect? otherwise I don't think it does, please comment)

alias sudo='my_sudo '

function my_sudo {
    while [[ $# > 0 ]]; do
        case "$1" in
        command) shift ; break ;;
        nocorrect|noglob) shift ;;
        *) break ;;
        esac
    done
    if [[ $# = 0 ]]; then
        command sudo zsh
    else
        noglob command sudo $@
    fi
}

Which satisfies both of my requirements from my question:

➜  ~  alias cat='echo hello'     
➜  ~  echo goodbye > example.txt
➜  ~  sudo cat
hello
➜  ~  sudo mv example.txt2 example.txt

It also seems that this came up again in 2008 on the mailing list with a solution like so:

alias sudo='noglob do_sudo '
function do_sudo
{
    integer glob=1
    local -a run
    run=( command sudo )
    if [[ $# -gt 1 && $1 = -u ]]; then
        run+=($1 $2)
        shift ; shift
    fi
    (($# == 0)) && 1=/bin/zsh
    while (($#)); do
        case "$1" in
        command|exec|-) shift; break ;;
        nocorrect) shift ;;
        noglob) glob=0; shift ;;
        *) break ;;
        esac
    done
    if ((glob)); then
        PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" $run $~==*
    else
        PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" $run $==*
    fi
}

Which seems to be doing a lot that I admittedly don't fully understand. This seems to ignore autocorrect (as stated by the author).