Bash可以给unexpected results if one edits a script while the script is running。但能够编辑我在shell中运行的脚本的临时副本通常会非常方便,但在我再次运行它之前,请确保它已回到原始位置。有没有人对Emacs的工作流程或定制有任何建议以促进这一点?Emacs工作流程在运行时编辑Bash脚本
回答
M-x delete-file
,按down
插入获得的路径,你正在编辑的文件,并RET
删除该文件。当你下一次保存你的缓冲区时,这将创建一个新文件。 Bash将继续执行旧的已删除文件。
顺便说一句,在大多数情况下,你甚至不需要采取这种预防措施。 Emacs通常保存到一个临时文件,然后将该临时文件重命名为正确的文件名(删除旧文件,除非它保留为备份)。如果Emacs检测到文件无法正确重新创建文件:如果该文件具有硬链接,或者您没有该目录的写入权限,则Emacs只会覆盖该文件。 (我正在简化一些;细节位于files.el
的basic-save-buffer-2
函数中。)只要文件具有单个目录条目,并且您对包含该脚本的目录具有写入权限,只需按C-x C-s
即可。
我已经有了重命名当前缓冲区文件的功能。是一个短暂的跳转到一个功能,它可以很容易地切换到临时版本的文件,然后再回来。基本上,如果您在访问普通文件“foo.txt”时运行此函数,它会将该文件复制到名为“tmp.foo.txt”的相同目录中的新文件。根据需要编辑。准备切换回来时,再次运行该功能,它会将临时文件移回原始文件。我使用了前缀“tmp”。而不是后缀,因为emacs中的大多数模式识别都基于后缀(您可以在记住所有缓冲模式并重新应用时做更有趣的事情)。
(defun toggle-temp-file()
(interactive)
(let* ((cur-buf (current-buffer))
(cur-file (buffer-file-name cur-buf))
(cur-file-dir (file-name-directory cur-file))
(cur-file-name (file-name-nondirectory cur-file))
new-file)
(if (string-match "^tmp\\.\\(.+\\)\\'" cur-file-name)
;; temp file -> orig file
(progn
(setq new-file
(concat cur-file-dir (match-string 1 cur-file-name)))
(rename-file cur-file new-file t))
;; orig file -> temp file
(setq new-file (concat cur-file-dir "tmp." cur-file-name))
(copy-file cur-file new-file nil nil t))
(kill-buffer cur-buf)
(find-file new-file)))
在这个答复,我
- 补充由吉尔漂亮的答案与理论。
- 提示emacs使用方面的改进。
- 纯粹通过shell脚本来建议替代方案。
警告:我不是一个专业程序员。
1理论
缺失的原因是安全的,但改变并非是在Unix中,已删除的文件变得不可访问从文件系统,但已经打开的文件的过程(在这里,/斌/庆典)仍然可以读取它,如解释here。并不是说bash做了一些特殊的事情,比如缓冲整个文件,但它只是读取。 (即使删除后,你可以在它的运行恢复脚本,as explained here在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)
但这是不完美的。它保存了文件模式,但仅此而已。
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 "[email protected]"
else
rm "$0"
fi
用例:保存/home/foo/a.sh此文件:如果你调用上面的脚本为./a.sh 1 2 3
#!/bin/sh
echo "$0 [email protected]"
. /home/foo/the-above-code.sh
echo "Again, $0 [email protected]"
,结果是:
/home/foo/a.sh 1 2 3
/tmp/.sh-tmp/a.sh 1 2 3
Again, /tmp/.sh-tmp/a.sh 1 2 3
这可能是最好的,但使用风险自负。
这也是众所周知的,把所有的大括号,最后exit
做的工作,如解释here。
刚刚添加该解决方案,以保护被更改运行BASH脚本一个简单而干净的方式:
#! /bin/bash
{
your_code;
exit;
}
在teika kazura的回答结束时也提到了,但仍然很方便地突出它我认为。 – phils
- 1. npm运行脚本流程不工作
- 2. 工作流程4运行时编译
- 3. 当在终端外运行时,Bash脚本不工作
- 4. 如何在工作时间持续运行bash脚本?
- 5. 编辑工作流程
- 6. 在运行时显示工作流程
- 7. Bash脚本:按行编辑.txt
- 8. bash脚本和编辑CSV
- 9. 如何在运行不同程序时运行bash脚本?
- 10. 自动运行时Bash脚本无法正常工作
- 11. 主动设置 - 脚本编辑文件没有运行/工作
- 12. 在Python中运行远程Bash脚本
- 13. 在bash脚本上做一个完整的工作流程
- 14. CurrentWorkItem.ID在工作流脚本编辑器中是否正确?
- 15. 在bash中运行脚本
- 16. bash脚本来编译和运行C++
- 17. 在bash脚本中编辑html/css
- 18. ASP.NET中的运行时工作流程
- 19. 并行运行bash脚本?
- 20. 并行运行bash脚本
- 21. 在Heroku中以编程方式运行bash脚本文件
- 22. 运行bash脚本时出现逻辑错误
- 23. 当我在脚本运行时编辑脚本时会发生什么?
- 24. 编写运行cygwin bash并执行程序的shell脚本
- 25. 什么是有效的C工作流程? - Makefile + bash脚本
- 26. cron作业没有运行bash脚本
- 27. 运行bash脚本作为守护
- 28. python结构运行远程bash脚本
- 29. Ubuntu:sshpass运行远程bash脚本
- 30. bash脚本来检查运行进程
这听起来很简单。我需要仔细检查一下,确实有效。如果是这样,这是否意味着Emacs现有的保存和重命名行为会阻止此问题出现? –
@MichaelHoffman是的,如果Emacs正在进行保存和重命名(这是大多数情况下的默认行为),那么您根本就不会有这个问题。请注意,我假设这里是一个真正的unix,如果你正在对Cygwin这样的东西运行bash,那么你可能无法删除这个文件(我对此不确定)。 – Gilles
你可以编辑你的答案,包括这个?看起来整个问题是不必要的,因为Emacs开箱即可做出正确的事情。 –