When performing system administration tasks, one often needs to edit files
owned by root
.
For both security and safety reasons, it's a good idea to do as little as
possible as root (or with root privileges). For that reason, you probably
don't want to run Emacs as 'root', because it's simply too powerful. I often
see people use vi
(usually, vim
) instead – but since it allows you to do
just about anything as well (like running shell commands), that's not much of
an improvement.
Now, a while back we discussed editing files owned by root with tramp – you
can use emacs with your normal user-account, and use sudo
to write the
root-owned file. That makes it much harder to screw things up.
Another reason people use vi
for little editing jobs is because its startup
time is significantly shorter than the startup time for a new emacs
instance. For that, however, we have emacs daemon.
Combining tramp and emacs daemon and a shell function:
# edit file with root privs function E() { emacsclient -c -a emacs "/sudo:root@localhost:$1" }
Now, we can very quickly edit any file owned by root using 'E' --
$ E /etc/hosts
So, if you prefer emacs, there's little reason to use vi
, even for editing
system files – although I have to admit that it takes time to evict 'sudo vi
<system file>' from my muscle memory.
Update reader Yi Wang mentions that, in fact, we can make this a bit more
general using sudoedit
; so, instead of using Tramp, we can use:
# edit file with root privs alias E="SUDO_EDITOR=\"emacsclient -c -a emacs\" sudoedit"
This works also without absolute paths.
13 comments:
Yes, I also used to edit via tramp. There is one annoying thing: I need to provide the absolute path. It doesn't work to "cd /etc" and then "E hosts".
Now I use an alternative way: export emacs as the user's default editor, and then sudoedit /etc/hosts
@Yi Wang: ah, that's clever; 'sudoedit' copies the file in the background to basically do the same thing that tramp does.
slightly modified version which takes care of relative paths:
function E() {
filename=$1
without_beg_slash="${1##/}"
if [[ $without_beg_slash == $1 ]];then
filename="${PWD%//}/$1"
fi
emacsclient -c -a emacs "/sudo:root@localhost:$filename"
}
Very useful.
How do you make both a frame- and terminal version of Yi Wang's solution?
export T_EDITOR="emacsclient -t"
and then using this for the terminal version didn't work.
Here is a way to reopen read only files with sudo automatically from inside Emacs :
http://tsdh.wordpress.com/2008/08/20/re-open-read-only-files-as-root-automagically/
man sudoedit:
The editor specified by the policy is run to edit the temporary files. The sudoers policy uses the SUDO_EDITOR, VISUAL and EDITOR environment variables (in that order). If none of SUDO_EDITOR, VISUAL or EDITOR are set, the first program listed in the editor sudoers(5) option is used.
@Anonymous: to have a separate terminal version, just define a second macro (in your .bashrc or equivalent):
alias T="SUDO_EDITOR=\"emacsclient -t -a emacs\" sudoedit"
now, "T" should do the right thing.
Just tried your solution and remembered what I disliked about it: Backupfiles in my homedirectory.
I saw a way to prevent this on the emacswiki somewhere, but I'd personally rather not take that risk.
Another option is to use zile which is a lightweight editor with Emacs shortcuts.
The tramp method is still useful since there is no 'sudoedit' on Mac OSX.
Can anyone see right offhand why this does NOT work?
Started emacs daemon with:
emacs --daemon=prog
So emacs daemon named prog running in bg.
Now in .bashrc:
'(set-background-color "DeepPink4")' -e '(set-foreground-color "beige")' -e '(set-cursor-color "khaki")'E () { emacsclient -e '(set-background-color "DeepPink4")' -e '(set-foreground-color "beige")' -e '(set-cursor-color "khaki")' -s prog -c -a emacs "/sudo:root@localhost:$1"; }
But when called like:
`E /root/somefile'
The frame is created for a moment and then closes. I see the error in xterm:
E /root/new_crontab
x
x
nil
-error Symbol's value as variable is void: /sudo:root@localhost:/root/new_crontab
'(set-background-color "DeepPink4")' -e '(set-foreground-color "beige")' -e '(set-cursor-color "khaki")'
What am I doing wrong?
A little piece of the .bashrc function got omitted so reproduced here in full:
E () { emacsclient -e '(set-background-color "DeepPink4")' -e '(set-foreground-color "beige")' -e '(set-cursor-color "khaki")'emacsclient -e '(set-background-color "DeepPink4")' -e '(set-foreground-color "beige")' -e '(set-cursor-color "khaki")' -s prog -c -a emacs "/sudo:root@localhost:$1"; }
function E() {
emacsclient -t -a "" "/sudo::$@"
}
This starts a new daemon as the user if it's not running already (-a "") and uses TRAMP so that there doesn't have to be another daemon for "root"
Post a Comment