Polite Bash Commands
Published 4 years, 1 month pastFor years, I’ve had a bash alias that re-runs the previous command via sudo
. This is useful in situations where I try to do a thing that requires root access, and I’m not root (because I am never root). Rather than have to retype the whole thing with a sudo
on the front, I just type please and it does that for me. It looked like this in my .bashrc
file:
alias please='sudo "$BASH" -c "$(history -p !!)"'
But then, the other day, I saw Kat Maddox’s tweet about how she aliases please
straight to sudo
, so to do things as root, she types please apt update, which is equivalent to sudo apt update. Which is pretty great, and I want to do that! Only, I already have that word aliased.
What to do? A bash function! After commenting out my old alias, here’s what I added to .bash_profile
:
please() {
if [ "$1" ]; then
sudo $@
else
sudo "$BASH" -c "$(history -p !!)"
fi
}
That way, if I remember to type please apachectl restart, as in Kat’s setup, it will ask for the root password and then execute the command as root; if I forget my manners and simply type apachectl restart, then when I’m told I don’t have privileges to do that, I just type please and the old behavior happens. Best of both worlds!
Comments (7)
Very cool! Time to be polite to AI. LOL!
Hi. Unfortunately, using
sudo $BASH -c
like that can sometimes run a different command to usingsudo
in the first place, because your command line is now being interpreted inroot
‘s environment rather than your own.For a trivial demo try:
It will affect any environment variable that you and
root
have set differently, and any path starting with~/
— which will lead either to an error message (root
‘s home directory doesn’t contain a file with that name) or, worse, operating on the wrong file (you’ve just copied an SSH key toroot
‘s.ssh/
directory rather than your own).To avoid this, instead of invoking a nested Bash process, use
eval
in your existing one:For what it’s worth, my variant of this function also manipulates Bash history to insert the command you actually wanted to run (so if you want to restart Apache again, pressing
Up
will give yousudo apachectl restart
, rather thanplease
). I’m less polite than you, so mine is calledrr
, for “redo as root”:That’s literally a tab and a space in the substitution line with a big gap in it. Omit the
echo
line if you don’t want the command being run to be displayed first.Er… it seems like you guys are making this way more complicated than it needs to be. Just use
!!
directly.Do you know the command : sudo !!
This put sudo in front of your previous command
The same thing as your alias
Not clear to me why you don’t just use
sudo $(history -p !!)
instead ofsudo "$BASH" -c "$(history -p !!)"
to avoid spinning up a shell with root permissions.Btw. instead of
history
you can also make use of thefc
builtin. I.e.sudo $(fc -ln 0)
.David, just doing
sudo $(history -p !!)
will fail if, for instance, the previous command has quote marks in it, or refers to a$FOO
environment variable, or uses~
for a home directory, or anything else which is interpreted by the shell.The command line needs interpreting with Bash before running the command, which
$(...)
doesn’t do — it just passes the text as arguments tosudo
literally.I’ve always used
↑^asudo ⏎
to go to the previous line and add sudo at the beginning and run it. That way if I want to re-run the command in the future, I can find it by going up and I don’t have to run two commands in order.