我正在使用 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 提供的原始脚本。