如果在脚本运行时编辑脚本, Bash可能会产生意外结果.但是,能够编辑我在shell中运行的脚本的临时副本通常会非常方便,但在再次运行它之前确保它回到原始位置.是否有人建议工作流程或自定义Emacs以促进这一点?
M-x delete-file,按下down以插入获取您正在编辑的文件的路径,并RET删除该文件.当您下次保存缓冲区时,这将创建一个新文件.Bash将继续执行旧的已删除文件.
顺便说一下,在大多数情况下,您甚至不需要采取这种预防措施.Emacs通常会保存到临时文件,然后将该临时文件重命名为正确的文件名(删除旧文件,除非将其保留为备份).如果文件检测到无法正确重新创建文件,则Emacs仅覆盖文件:如果文件具有硬链接,或者您对目录没有写入权限.(我正在简化一些;详细信息在basic-save-buffer-2函数中files.el.)只要文件有一个目录条目,并且您对包含脚本的目录具有写权限,只需按C-x C-s.
在这个回复中,我
警告:我不是专业的程序员.
1理论
缺失的原因是安全的,但改变并非是在Unix中,已删除的文件从文件系统得到人迹罕至,但已经打开的文件的过程(在这里,/斌/庆典)仍然可以读取它,解释在这里.这不是bash做一些特别的事情,比如缓冲整个文件,但它只是读取.(即使在删除之后,您也可以在脚本运行时恢复脚本,如此处所述.在bash中,脚本似乎始终打开为255 , /proc/<pid>/fd/255.)
2 Emacs解决方案
现在emacs; 为了安全起见,您可以自动化所有; 添加到before-save-hook函数以检查它是否为sh模式,并在脚本打开时自动删除,方法是检查lsof:
(defvar delete-open-sh-flag nil
"Used by `delete-open-sh.` If nil, deletion didn't happen.
Otherwise, the mode is saved.")
(defun delete-open-sh ()
(setq delete-open-sh-flag nil)
(when (and (eq major-mode 'sh-mode)
(buffer-file-name)
(file-exists-p (buffer-file-name)))
(let ((buf (generate-new-buffer " *foo*")))
(call-process "lsof" nil; infile
buf ; dest
nil ; display
(buffer-file-name))
(unless (eq 0 (buffer-size buf))
(setq delete-open-sh-flag (file-modes (buffer-file-name)))
(delete-file (buffer-file-name)))
(kill-buffer buf))))
(defun delete-open-sh-after ()
(when delete-open-sh-flag
(set-file-modes (buffer-file-name) delete-open-sh-flag)))
(add-hook 'before-save-hook 'delete-open-sh)
(add-hook 'after-save-hook 'delete-open-sh-after)
Run Code Online (Sandbox Code Playgroud)
但这并不完美.它保存了文件模式,但就是这样.
3纯粹的bash解决方案
或者,您可以让bash脚本本身执行删除操作.用这个:
# Usage: . /path/to/this-script (Always use abs path)
# Restart the caller script itself in a temporary file; this allows
# editing of the caller script file while it's run.
# Temporary file is soon deleted.
#
if [[ ! "`dirname $0`" =~ ^/tmp/.sh-tmp ]]; then
mkdir -p /tmp/.sh-tmp/
DIST="/tmp/.sh-tmp/$( basename $0 )"
install -m 700 "$0" $DIST
exec $DIST "$@"
else
rm "$0"
fi
Run Code Online (Sandbox Code Playgroud)
用法示例:将此文件保存在/home/foo/a.sh中:
#!/bin/sh
echo "$0 $@"
. /home/foo/the-above-code.sh
echo "Again, $0 $@"
Run Code Online (Sandbox Code Playgroud)
如果您调用上面的脚本./a.sh 1 2 3,结果是:
/home/foo/a.sh 1 2 3
/tmp/.sh-tmp/a.sh 1 2 3
Again, /tmp/.sh-tmp/a.sh 1 2 3
Run Code Online (Sandbox Code Playgroud)
这可能是最好的,但使用风险自负.
它也知道,把所有的梅开二度,以缔结exit做这项工作,为解释在这里.