5
\$\begingroup\$

I wrote this little Bash function to replace my sudo command.

It checks whether I have an alias for the given command and runs the aliased command instead of the literal one in that case.

As this is going to be used with sudo, I want to be sure there are no critical mistakes in it which generate security or safety issues. Please check whether everything is okay with it, like quoting issues or improvements to the sed pattern maybe. Thanks.

Here is my function:

sudo() { if alias "$1" &> /dev/null ; then $(type "$1" | sed -E 's/^.*`(.*).$/\1/') "${@:2}" ; else command sudo $@ ; fi }

Or nicely formatted:

sudo() { 
    # check if the command passed as argument is an alias
    if alias "$1" &> /dev/null ; then 
        # extract the aliased command from the output of 'type'
        # and run it with the remaining arguments
        $(type "$1" | sed -E 's/^.*`(.*).$/\1/') "${@:2}"
    else 
        # run the original 'sudo' command with all arguments
        command sudo $@
    fi 
}
\$\endgroup\$
6
\$\begingroup\$

First of all, you need to quote $@:

command sudo "$@"

If you don't your function will break if the command you pass to sudo contains a space in its path.

Then, this will break if your input is aliased to something which contains a backtick. For example:

$ alias foo='ls `which sudo`'
$ type foo
foo is aliased to `ls `which sudo`'

Now, the output of your sed command is not what you expect:

$ type foo | sed -E 's/^.*`(.*).$/\1/' 
$ 

That will return nothing since the ^.*` means "match the longest possible string from the beginning of the string to a backtick" and, therefore, will match everything except the final '. A better approach would be to use a tool that has non-greedy matching like perl:

$ type foo | perl -pe 's/^.*?\`(.*).$/\1/'
ls `which sudo`

You will also need to eval it in order for it to run correctly:

$ "$(type foo | perl -pe 's/^.*?\`(.*).$/\1/')"
bash: ls `which sudo`: command not found
$ eval $(type foo | perl -pe 's/^.*?\`(.*).$/\1/')
/sbin/sudo

Putting all this together, gives:

sudo() { 
    # check if the command passed as argument is an alias
    if alias "$1" &> /dev/null ; then 
        # extract the aliased command from the output of 'type'
        # and run it with the remaining arguments
        eval $(type "$1" | perl -pe 's/^.*?\`(.*).$/\1/' "${@:2}")
    else 
        # run the original 'sudo' command with all arguments
        command sudo "$@"
    fi 
}

I can't guarantee that it will work for all cases though. All things considered, I wouldn't use this approach at all. I would instead use

alias sudo='sudo '

As explained here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.