You can't just stick sudo
in front of a shell command, you have to invoke a shell to evaluate that command again (doing things like expanding variables, opening files for redirection operators, etc.). So that's
sudo bash -c !!
except that this doesn't quite work, because !!
interpolates the text of the previous command, special characters and all. You need to retrieve the text of the command as a string and pass that as an argument to sh
. Fortunately, bash's fc
builtin lets you do that¹.
sudo bash -c "$(fc -ln -1)"
Or even, to be sure to invoke the same version of bash that's currently running:
sudo "$BASH" -c "$(fc -ln -1)"
Note that since the command is executed in a separate shell process, it inherits environment variables (only the ones that sudo
preserves, mind), but not shell internal variables. Shell options (e.g. kshglob
) and other settings will start from the default either.
The same command² works in zsh and ksh, though ATT ksh93 requires both the first
and last
number to be passed to fc
³ (which also works in bash, zsh and pdksh/mksh):
sudo zsh -c "$(fc -ln -1)"
sudo ksh -c "$(fc -ln -1 -1)"
sudo "$0" -c "$(fc -ln -1 -1)"
Using $0
to designate the executable of the running shell works only if the shell was invoked through the $PATH and the $PATH hasn't changed, or through an absolute path.
Here's another method in zsh which is slightly clearer but longer:
sudo zsh -c $history[$[HISTCMD-1]]
A final word of warning: sudo
is for potentially dangerous commands. Don't make it too easy to use it!
¹ There's some extra whitespace at the beginning and the command substitution strips off newlines at the end, but the syntax of the shell doesn't care about that.
² I don't think zsh or ksh have anything like bash's $BASH
; $0
only works when it's an absolute path, or when it contains no slash and the command search path hasn't changed.
³ fc
is an alias for hist
in ATT ksh but that's just as good.
alias sudo !!
? – Gilles 'SO- stop being evil' Jun 20 '14 at 21:09