如何在文件更改时执行命令?

如何在文件更改时执行命令?

我想要一种快速而简单的方法来在文件更改时执行命令。我想要一个非常简单的方法,一个可以在终端上运行并在处理完该文件后关闭的方法。

目前,我正在使用这个:

while read; do ./myfile.py ; done

然后,每当我在编辑器上保存该文件时,我都需要转到该终端并按Enter。我想要的是这样的:

while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done

或者任何其他同样简单的解决方案。

顺便说一句:我正在使用 Vim,我知道我可以添加一个自动命令来在 BufWrite 上运行某些操作,但这不是我现在想要的解决方案。

更新:我想要一些简单、可丢弃的东西。此外,我想要一些可以在终端中运行的东西,因为我想看到程序输出(我想看到错误消息)。

关于答案:感谢大家的回答!所有答案都非常好,而且每个答案都采用了截然不同的方法。由于我只需要接受一个,所以我接受了我实际使用过的一个(它简单、快速且易于记忆),尽管我知道它不是最优雅的。

答案1

很简单,使用通知等待(安装你的发行版的inotify-tools软件包):

while inotifywait -e close_write myfile.py; do ./myfile.py; done

或者

inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
  ./myfile.py         # or "./$filename"
done

第一个代码片段比较简单,但它有一个明显的缺点:它会错过在inotifywait未运行时执行的更改(特别是myfile在运行时)。第二个代码片段没有这个缺陷。但是,请注意,它假定文件名不包含空格。如果这是一个问题,请使用选项--format将输出更改为不包含文件名:

inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
  ./myfile.py
done

不管怎样,都有一个限制:如果某个程序myfile.py用不同的文件替换,而不是写入现有的myfileinotifywait就会死机。许多编辑器都是这样工作的。

为了克服这个限制,请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

或者,使用其他使用相同底层功能的工具,例如因克龙(允许您在文件被修改时注册事件)或样本(该工具也适用于许多其他 Unix 变体,使用每个变体的 Linux 的 inotify 类似物)。

答案2

进入https://github.com/eradman/entr) 为 inotify 提供了更加友好的界面(并且还支持 *BSD 和 Mac OS X)。

它可以很容易地指定要监视的多个文件(仅受限制ulimit -n),省去了处理被替换文件的麻烦,并且需要更少的 bash 语法:

$ find . -name '*.py' | entr ./myfile.py

我一直在我的整个项目源代码树上使用它来运行我当前正在修改的代码的单元测试,它已经极大地促进了我的工作流程。

-c诸如(运行之间清除屏幕)和-d(当新文件添加到受监视目录时退出)之类的标志增加了更多的灵活性,例如您可以执行以下操作:

$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done

截至 2018 年初,它仍处于积极开发中,可以在 Debian 和 Ubuntu(apt install entr)中找到;无论如何,从作者的 repo 构建都很轻松。

答案3

我编写了一个 Python 程序来做这件事,叫做何时改变

使用方法很简单:

when-changed FILE COMMAND...

或者观看多个文件:

when-changed FILE [FILE ...] -c COMMAND

FILE可以是目录。使用 递归监视-r。使用%f将文件名传递给命令。

答案4

对于那些无法inotify-tools像我一样安装的人来说,这应该是有用的:

watch -d -t -g ls -lR

当输出改变时,此命令将退出,ls -lR将列出每个文件和目录及其大小和日期,因此如果文件发生变化,它应该退出命令,正如 man 所说:

-g, --chgexit
          Exit when the output of command changes.

我知道这个答案可能没有人会读到,但我希望有人能够看到它。

命令行示例:

~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"

打开另一个终端:

~ $ echo "testing" > /tmp/test

现在第一个终端将输出1,2,3

简单脚本示例:

#!/bin/bash
DIR_TO_WATCH=${1}
COMMAND=${2}

watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}

相关内容