The key part in this behavior is explained by 2 bits in the bash manpage:
In the HISTORY EXPANSION
section:
History expansion is performed immediately after a complete line is read, before the shell breaks it into words.
In the ALIASES
section:
The first word of each simple command, if unquoted, is checked to see if it has an alias.
So basically history expansion occurs before word splitting. Alias expansion occurs after.
Alternate solution
The best way I can think of doing this is the following:
alias root='sudo $(fc -ln -1)'
This will work for simple commands, but for more complex ones we need to tweak it.
alias root='sudo sh -c "$(fc -ln -1)"'
The reason for the change is because of something like this:
# alias root='sudo $(fc -ln -1)'
# echo "I AM $(whoami)"
I AM patrick
# root
"I AM $(whoami)"
As you can see no shell parsing is done. By changing it to use sh -c "..."
instead, it does shell interpretation.
# alias root='sudo sh -c "$(fc -ln -1)"'
# echo "I AM $(whoami)"
I AM patrick
# root
I AM root
Another way (I thought of this one first, so keeping it in the answer, but it's not as nice as the one above):
alias root='fc -e "sed -i -e \"s/^/sudo /\""'
The fc -e
command will run the specified command passing it a file containing the previously executed command. We just run sed
on that file to prefix the command with sudo
.
ls; sudo !!
that will work by itself in a shell. – slm Dec 05 '13 at 12:28fc
suggests an alias, so this is more likely to be a problem of switching users/shells. – lynxlynxlynx Dec 05 '13 at 12:33!!
to an alias, and have the alias expand it later. – slm Dec 05 '13 at 12:49!!
is actually expanded when defining the alias, so the alias will sudo-execute the command last used before the definition instead of the command used before calling the alias. – crater2150 Dec 06 '13 at 09:18