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

07
2014-07
  • Mike H-R

    Until Recently I had alias sudo='sudo ' in my .zshrc file. Today I ran into this error on trying to do sudo mv:

    ➜  ~  sudo mv nginx.conf.orig nginx.conf.orig2
    sudo: nocorrect: command not found
    

    Now googling around I found out that this seemed to be to do with some commands that are prefixed with nocorrect and that I could fix this with alias sudo='nocorrect sudo'.

    However the problem comes when I try to set my alias to alias sudo='nocorrect sudo ' to allow myself to use additional aliases. I also ensured that my su was using zsh as mentioned here.

    ➜  ~  alias sudo='nocorrect sudo '            
    ➜  ~  sudo mv nginx.conf.orig nginx.conf.orig2
    sudo: nocorrect: command not found
    ➜  ~  alias sudo='nocorrect sudo'                           
    ➜  ~  sudo mv nginx.conf.orig nginx.conf.orig2
    ➜  ~  su
    Password: 
    michaelarch# ps -p $$
      PID TTY          TIME CMD
    25831 pts/1    00:00:00 zsh
    

    Does anyone have any suggestions on how to resolve this?

    EDIT: alias sudo='sudo ' allows you to use aliases with your sudo commands, for an example see below.

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

    For some more info on my shell:

    ➜  ~  sudo chsh                               
    Changing shell for root.
    New shell [/usr/bin/zsh]:    
    ➜  ~  unalias sudo; alias sudo='nocorrect sudo '
    ➜  ~  echo $SHELL; which sudo                   
    /usr/bin/zsh
    sudo: aliased to nocorrect sudo 
    ➜  ~  sudo mv nginx.conf.orig2 nginx.conf.orig  
    sudo: nocorrect: command not found
    ➜  ~  which mv
    mv: aliased to nocorrect mv
    
  • Answers
  • mpy

    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.

  • Mike H-R

    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).

  • terdon

    The problem, as I explain in my answer here, is that sudo starts a separate shell. On most, if not all, Linux distributions, the default shell is bash and not zsh. Since nocorrect is a zsh builtin, it is not available in bash and so you get the command not found error.

    The solution is to set sudo to sue zsh as well:

    sudo chsh
    

    Then set it to /usr/bin/zsh. That should make sudo start a zsh shell and your alias will work as expected.


  • Related Question

    linux - sudo su runs without password prompt?
  • Ed Manet

    So here's the problem. We've got the /etc/sudoers file set up so that users can run commands from /bin like "cat" or "mkdir" without entering a password. The problem is that the "su" command is also in /bin, so if they enter "sudo su", it gives them root access without a password. Here's the /etc/sudoers file:

    Defaults targetpw    
    %users ALL=(ALL) ALL 
    
    root    ALL=(ALL) ALL
    
    support ALL=(ALL) NOPASSWD: /sbin/, /bin/, /opt/, /etc/init.d/, /elo/
    support ALL=(ALL) NOPASSWD: /usr/bin/mysql
    

    Is there a way I can deny /bin/su while still allowing the rest of the /bin commands?


  • Related Answers
  • Turbo J

    They can mount? Then they have everything to become superuser. There are some other interesting commends, too.

    You really want to make /etc/sudoers a white-list, and not a black-list.

    With proper file and directory access bits and user/group setings, you should not need sudo in your daily work.