Den*_*aia 549 linux unix script shell
我想要一种快速而简单的方法来在文件更改时执行命令。我想要一些非常简单的东西,我会在终端上运行并在我完成处理该文件时关闭它。
目前,我正在使用这个:
while read; do ./myfile.py ; done
Run Code Online (Sandbox Code Playgroud)
然后Enter,每当我将该文件保存在我的编辑器中时,我都需要转到该终端并按。我想要的是这样的:
while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done
Run Code Online (Sandbox Code Playgroud)
或任何其他简单的解决方案。
顺便说一句:我正在使用 Vim,我知道我可以添加一个自动命令来在 BufWrite 上运行一些东西,但这不是我现在想要的那种解决方案。
更新:如果可能的话,我想要一些简单的、可丢弃的。更重要的是,我想在终端中运行一些东西,因为我想查看程序输出(我想查看错误消息)。
关于答案:感谢您的所有回答!他们都非常好,每个人都采用与其他人截然不同的方法。因为我只需要接受一个,所以我接受了我实际使用过的一个(它简单、快速且易于记忆),尽管我知道它不是最优雅的。
Gil*_*il' 501
简单,使用inotifywait(安装您的发行版的inotify-tools
包):
while inotifywait -e close_write myfile.py; do ./myfile.py; done
Run Code Online (Sandbox Code Playgroud)
或者
inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
./myfile.py # or "./$filename"
done
Run Code Online (Sandbox Code Playgroud)
第一个片段更简单,但它有一个明显的缺点:它会错过inotifywait
未运行时(尤其myfile
是运行时)执行的更改。第二个片段没有这个缺陷。但是,请注意它假定文件名不包含空格。如果这是一个问题,请使用该--format
选项将输出更改为不包含文件名:
inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
./myfile.py
done
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,都有一个限制:如果某个程序替换myfile.py
为不同的文件,而不是写入现有的myfile
,inotifywait
则会死亡。许多编辑都是这样工作的。
要克服此限制,请inotifywait
在目录上使用:
inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
if [ "$filename" = "myfile.py" ]; then
./myfile.py
fi
done
Run Code Online (Sandbox Code Playgroud)
或者,使用另一个使用相同底层功能的工具,例如incron(允许您在修改文件时注册事件)或fswatch(一个也适用于许多其他 Unix 变体的工具,使用每个变体的 Linux inotify 模拟)。
Pau*_*ney 223
entr ( http://entrproject.org/ ) 为 inotify 提供了更友好的界面(并且还支持 *BSD 和 Mac OS X)。
它使得指定多个要监视的文件变得非常容易(仅受 限制ulimit -n
),消除了处理被替换文件的麻烦,并且需要更少的 bash 语法:
$ find . -name '*.py' | entr ./myfile.py
Run Code Online (Sandbox Code Playgroud)
我一直在我的整个项目源代码树上使用它来运行我当前正在修改的代码的单元测试,它已经对我的工作流程产生了巨大的推动作用。
像-c
(在运行之间清除屏幕)和-d
(在将新文件添加到受监视目录时退出)之类的标志增加了更多的灵活性,例如您可以执行以下操作:
$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
Run Code Online (Sandbox Code Playgroud)
截至 2018 年初,它仍在积极开发中,可以在 Debian 和 Ubuntu ( apt install entr
) 中找到;在任何情况下,从作者的 repo 构建都是无痛的。
joh*_*joh 132
我写了一个 Python 程序来完成这个叫做when-changed 的事情。
用法很简单:
when-changed FILE COMMAND...
Run Code Online (Sandbox Code Playgroud)
或观看多个文件:
when-changed FILE [FILE ...] -c COMMAND
Run Code Online (Sandbox Code Playgroud)
FILE
可以是目录。用 递归观察-r
。使用%f
的文件名传递给此命令。
小智 61
这个剧本怎么样?它使用stat
命令来获取文件的访问时间,并在访问时间发生变化时(每当文件被访问时)运行命令。
#!/bin/bash
### Set initial time of file
LTIME=`stat -c %Z /path/to/the/file.txt`
while true
do
ATIME=`stat -c %Z /path/to/the/file.txt`
if [[ "$ATIME" != "$LTIME" ]]
then
echo "RUN COMMAND"
LTIME=$ATIME
fi
sleep 5
done
Run Code Online (Sandbox Code Playgroud)
Den*_*aia 33
使用 Vim 的解决方案:
:au BufWritePost myfile.py :silent !./myfile.py
Run Code Online (Sandbox Code Playgroud)
但我不想要这个解决方案,因为它打字有点烦人,很难记住要输入什么,确切地说,并且撤消它的效果有点困难(需要运行:au! BufWritePost myfile.py
)。此外,这个解决方案会阻塞 Vim,直到命令完成执行。
我在这里添加了这个解决方案只是为了完整性,因为它可能会帮助其他人。
要显示程序输出(并完全中断您的编辑流程,因为输出将覆盖编辑器几秒钟,直到您按 Enter),请删除该:silent
命令。
小智 33
对于那些不能inotify-tools
像我一样安装的人,这应该很有用:
watch -d -t -g ls -lR
当输出更改时,此命令将退出,ls -lR
将列出每个文件和目录及其大小和日期,因此如果文件更改,它应该退出命令,如 man 所说:
-g, --chgexit
Exit when the output of command changes.
Run Code Online (Sandbox Code Playgroud)
我知道这个答案可能不会被任何人阅读,但我希望有人能找到它。
命令行示例:
~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"
Run Code Online (Sandbox Code Playgroud)
打开另一个终端:
~ $ echo "testing" > /tmp/test
Run Code Online (Sandbox Code Playgroud)
现在第一个终端将输出 1,2,3
简单的脚本示例:
#!/bin/bash
DIR_TO_WATCH=${1}
COMMAND=${2}
watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
Run Code Online (Sandbox Code Playgroud)
Jon*_*ley 25
rerun2
(在 github 上)是以下形式的 10 行 Bash 脚本:
#!/usr/bin/env bash
function execute() {
clear
echo "$@"
eval "$@"
}
execute "$@"
inotifywait --quiet --recursive --monitor --event modify --format "%w%f" . \
| while read change; do
execute "$@"
done
Run Code Online (Sandbox Code Playgroud)
在 PATH 上将 github 版本另存为“重新运行”,并使用以下命令调用它:
rerun COMMAND
Run Code Online (Sandbox Code Playgroud)
每次在当前目录中发生文件系统修改事件时,它都会运行 COMMAND(递归)。
人们可能喜欢它的事情:
人们可能不喜欢它的事情:
这是对@cychoi 的回答的改进。
小智 14
如果你安装了nodemon,那么你可以这样做:
nodemon -w <watch directory> -x "<shell command>" -e ".html"
Run Code Online (Sandbox Code Playgroud)
就我而言,我在本地编辑 html 并在文件更改时将其发送到我的远程服务器。
nodemon -w <watch directory> -x "scp filename jaym@jay-remote.com:/var/www" -e ".html"
Run Code Online (Sandbox Code Playgroud)
小智 13
这是一个简单的 shell Bourne shell 脚本:
按下 Ctr-C 后会自行清理
#!/bin/sh
f=$1
shift
cmd=$*
tmpf="`mktemp /tmp/onchange.XXXXX`"
cp "$f" "$tmpf"
trap "rm $tmpf; exit 1" 2
while : ; do
if [ "$f" -nt "$tmpf" ]; then
cp "$f" "$tmpf"
$cmd
fi
sleep 2
done
Run Code Online (Sandbox Code Playgroud)这适用于 FreeBSD。我能想到的唯一可移植性问题是,如果其他一些 Unix 没有 mktemp(1) 命令,但在这种情况下,您可以硬编码临时文件名。
小智 8
NodeJs 的另一个解决方案fsmonitor:
安装
sudo npm install -g fsmonitor
Run Code Online (Sandbox Code Playgroud)从命令行(例如,如果一个日志文件更改,则监视日志和“零售”)
fsmonitor -s -p '+*.log' sh -c "clear; tail -q *.log"
Run Code Online (Sandbox Code Playgroud)小智 7
看看 Guard,特别是这个插件:
https://github.com/hawx/guard-shell
您可以将其设置为监视项目目录中任意数量的模式,并在发生更改时执行命令。即使有一个插件可用于您首先尝试做的事情,也很有可能。
小智 6
如果您的程序生成某种日志/输出,您可以创建一个 Makefile,其中包含该日志/输出的规则,该规则取决于您的脚本并执行类似操作
while true; do make -s my_target; sleep 1; done
Run Code Online (Sandbox Code Playgroud)
或者,您可以创建一个虚假目标并使其规则既调用您的脚本又触摸虚假目标(同时仍然取决于您的脚本)。
在 Linux 下:
man watch
watch -n 2 your_command_to_run
Run Code Online (Sandbox Code Playgroud)
将每 2 秒运行一次命令。
如果您的命令运行时间超过 2 秒,watch 将等到它完成后再执行。
我喜欢它的简单性,while inotifywait ...; do ...; done
但它有两个问题:
do ...;
将被错过因此,我制作了一个使用inotifywait且没有这些限制的帮助程序脚本:inotifyexec
我建议你把这个脚本放在你的路径中,比如在~/bin/
. 只需运行命令即可描述用法。
例子:inotifyexec "echo test" -r .
小智 6
Watchdog是一个 Python 项目,可能正是您要找的:
支持的平台
- Linux 2.6 (inotify)
- Mac OS X (FSEvents, kqueue)
- FreeBSD/BSD (kqueue)
- Windows(带有 I/O 完成端口的 ReadDirectoryChangesW;ReadDirectoryChangesW 工作线程)
- 独立于操作系统(轮询磁盘以获取目录快照并定期比较它们;缓慢且不推荐)
刚刚为它写了一个命令行包装器watchdog_exec
:
在涉及当前目录下的文件和文件夹的 fs 事件上,运行echo $src $dst
命令,除非 fs 事件被修改,然后运行python $src
命令。
python -m watchdog_exec . --execute echo --modified python
Run Code Online (Sandbox Code Playgroud)
使用短参数,并限制只在事件涉及“ main .py”时执行:
python -m watchdog_exec . -e echo -a echo -s __main__.py
Run Code Online (Sandbox Code Playgroud)
编辑:刚刚发现 Watchdog 有一个名为 的官方 CLI watchmedo
,所以也请检查一下。
swarminglogic写了一个脚本调用watchfile.sh,也可作为GitHub的要点。
改进了Gilles 的回答。
此版本运行inotifywait
一次,然后监视事件(.eg: modify
)。这样inotifywait
并不需要进行时遇到的每一个事件重新执行。
它又快又快!(即使在递归监视大目录时)
inotifywait --quiet --monitor --event modify FILE | while read; do
# trim the trailing space from inotifywait output
REPLY=${REPLY% }
filename=${REPLY%% *}
# do whatever you want with the $filename
done
Run Code Online (Sandbox Code Playgroud)
小智 5
使用命令改进了Sebastian 的解决方案watch
:
watch_cmd.sh
:
#!/bin/bash
WATCH_COMMAND=${1}
COMMAND=${2}
while true; do
watch -d -g "${WATCH_COMMAND}"
${COMMAND}
sleep 1 # to allow break script by Ctrl+c
done
Run Code Online (Sandbox Code Playgroud)
调用示例:
watch_cmd.sh "ls -lR /etc/nginx | grep .conf$" "sudo service nginx reload"
Run Code Online (Sandbox Code Playgroud)
它可以工作,但要小心:watch
命令有已知的错误(请参阅 man):它仅对输出终端部分中可见的更改做出反应-g CMD
。
你可以试试反射。
Reflex 是一个小工具,用于监视目录并在某些文件更改时重新运行命令。它非常适合自动运行编译/lint/测试任务以及在代码更改时重新加载应用程序。
# Rerun make whenever a .c file changes
reflex -r '\.c$' make
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
431797 次 |
最近记录: |