Sudoedit Vim 强制写入(更新)而不退出

Sudoedit Vim 强制写入(更新)而不退出

我正在使用 Vim 编写一些脚本,并且刚刚开始使用sudoedit.

问题是,当我:w写入临时文件时,除非退出编辑器,否则任何脚本测试都不会发生。

我如何强制更新原始版本,或者我错过了要点sudoedit

答案1

sudoedit允许您使用以您自己的用户 ID 运行的编辑器来编辑文件。它将文件复制到一个临时文件,然后编辑器可以写入该临时文件。一旦编辑器关闭,编辑过的文件就会被复制回来。

当编辑器仍在运行时,没有内置的可能性自动写回更改。

所以你需要

  • 在其他用户 ID 上运行编辑器(例如sudo vi /file/to/edit
  • 将文件手动复制回(单独的)shell ( sudo cp /tmp/... /file/to/edit) 或从 vim 内部:!sudo cp % /file/to/edit。在 vim 中,您还可以使用 Ctrl+Z 启动 shell:sh或将 vim 置于后台,然后使用 恢复它fg
  • 使用https://stackoverflow.com/questions/2600783/how-does-the-vim-write-with-sudo-trick-work
  • 创建您自己的版本,sudoedit一旦临时文件发生更改,该版本就会将更改写回。通过一些脚本应该可以轻松实现这一点。 Inotify 可以帮助您检测更改(参见示例bash 脚本可以连接到文件吗?

答案2

您错过了 sudoedit 的要点,但手册没有解释它,所以不用担心。

大多数编辑器都有 shell 转义,例如:shell在 vim 中,它允许您获得 root shell,即使您在 sudo 下可能没有此类权限。这称为“权限升级”,是一件坏事。

sudoedit命令的作用相当于:

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

请注意,编辑器以您而非 root 身份运行,因此您无法使用编辑器进行权限升级。

如果您拥有非常宽松的 sudo 权限(根据发行版,单用户计算机上通常会出现这种情况),您可以

$ sudo vim source-file

得到你想要的行为。

答案3

我自己做了一个sudoedit,用于inotifywait监听对临时文件的写入并更新原始文件。它仍然$EDITOR以调用脚本的用户身份运行您,就像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"

答案4

这是我目前正在使用的版本。以前的对我来说已经坏了。

#!/bin/bash

abs_filepath() {
    echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}

su_cat() {
    sudo sh -c 'cat "$1" > "$2"' -- "$1" "$2"
}

file_name="${1##*/}"
file_path="$(abs_filepath "$1")"
extension=$([[ "$file_name" = ?*.* ]] && printf ".${file_name##*.}" || printf '')
tmp="$(mktemp /var/tmp/$file_name.XXXXXXXXXXXX$extension)"

[ -f "$file_path" ] && sudo cat "$file_path" > "$tmp"

(
    while true; do
        # dummy variable to wait for an event
        _=$(inotifywait -q -e create -e moved_to -e close_write "$tmp")
        if [ -f "$tmp" ]; then
            su_cat "$tmp" "$file_path"
        fi
    done
) &

listener_pid=$!

nvim "$tmp"

kill $listener_pid
# wait for the process to finish. Simple `wait` doesn't work here
while $(kill -0 $listener_pid 2>/dev/null); do
    sleep 0\.5
done
su_cat "$tmp" "$file_path"

rm "$tmp"

我修复了一些错误。主要问题是 vim/nvim 编辑器。他们有一种复制文件、编辑文件然后复制回来的机制。因此,由于实际的 tmp 文件被删除,它被破坏了。

但再次感谢 Marcel 和 Processor 提供的原始脚本。

相关内容