6

I'm doing some scripting with Vim and I've just started using sudoedit.

Problem is, when I :w it writes to the temp file, so any testing of the script can't happen unless I quit the editor.

How can I force an update of the original, or am I missing the point of sudoedit?

Ben
  • 165

4 Answers4

14

sudoedit allows you to edit a file with an editor running on your own user id. It copies the file to a temporary file which your editor can then write into. As soon as the editor is closed, the edited file is copied back.

There is no built-in possibility to automatically write changes back while the editor is still running.

So you need either

  • run the editor on the other user id (e.g. sudo vi /file/to/edit )
  • copy the file manually back in a (separate) shell (sudo cp /tmp/... /file/to/edit) or from inside vim :!sudo cp % /file/to/edit. From vim you can also start a shell with :sh or put vim in the background with Ctrl+Z and restore it with fg.
  • use https://stackoverflow.com/questions/2600783/how-does-the-vim-write-with-sudo-trick-work
  • create your own version of sudoedit which writes changes back as soon as the temporary files is changed. This should be easily doable with some scripting. Inotify can help you to detect changes (see for example Can a bash script be hooked to a file? )
jofel
  • 26,758
  • 1
    Great answer, especially the comprehensive alternatives! – Ingo Karkat Sep 16 '13 at 12:53
  • OK thanks, yeah, I'd had a look at those docs (in @msw answer also). So, at the end of the day, I've still got to open the file with sudo anyway. – Ben Sep 17 '13 at 10:42
  • You don't need separate shell: if you're using bash, press Ctrl+Z in command mode (i.e. default mode) in vim - you'll put vim in background. After you do your work, you can use fg %n (or just %n) with whatever n vim gets (bash will print the number after you Ctrl+Z) to get vim back in foreground. – Ruslan Sep 17 '13 at 12:00
  • @Ruslan thanks for you comment. I extended the answer. In most cases, vim should become the current job of the shell, so fg without arguments should work. – jofel Sep 17 '13 at 12:18
  • Yeah, true in cases when you don't e.g. have multiple vim instances running in same shell and need earlier one :) . In this case you can even just use % without fg. – Ruslan Sep 17 '13 at 12:36
6

You are missing the point of sudoedit, but the manual doesn't explain it so fret not.

Most editors have shell escapes, for example :shell in vim which would allow you to gain a root shell even though you might not have such permission under sudo. This is called "privilege escalation" and is a Bad Thing.

The sudoedit command does the equivalent of:

# cp source-file /tmp/some-temporary-name
$ ${EDITOR} /tmp/some-temporary-name
# cp /tmp/some-temporary-name source-file
# rm /tmp/some-temporary-name

Note that the editor is run as you, not root, so you cannot use the editor for privilege escalation.

If you have very permissive sudo rights (as is often the case on single user machines depending on the distribution) you can

$ sudo vim source-file

to get the behavior you want.

msw
  • 10,593
  • Just because the editor is run as your user doesn't mean sudoedit can't listen for writes to the temporary file and move them over to the root file – Marcel Feb 21 '21 at 20:13
1

I made my own sudoedit that uses inotifywait to listen for writes to the temporary file and updates the original file. It still runs your $EDITOR as the user that called the script, just like sudoedit.

#!/bin/bash

tmp="/tmp/$(mktemp $(basename $1).XXXXXXXXXXXX)"

sudo cat "$1" > "$tmp" inotifywait -m "$tmp" -e create -e moved_to -e close_write 2>/dev/null >
>(sudo sh -c "while read path action file; do cp '$tmp' '$1'; done") &

pid=$!

sh -c "$EDITOR $tmp" kill $pid /usr/bin/rm "$tmp"

Marcel
  • 485
1

I slightly modified @Marcel's script. It did not work for me, I could not tell why.

This is what I did :

#!/bin/bash

extension=$(echo $1 | rev | cut -d'.' -f1 | rev) fName=$(basename $1 .$extension) tmp=$(mktemp /var/tmp/$fName.XXXXXXXXXXXX.$extension)"

sudo cat "$1" > "$tmp" ( while true;do changeControl=$(inotifywait -e modify "$tmp" 2>/dev/null) sudo cp $tmp $1 done ) &

pid=$!

nvim $tmp kill $pid rm "$tmp"

The script extracts the extension of the source file and uses it for the temp file. This way, plugins like phpactor or intelephense still works.

Then it runs the while in parallel and waits for any change.

Anyway thanks Marcel for your primary proposition that led me to a solution.

Ben
  • 165
Processor
  • 111