Mac 上是不是有类似“watch”或“inotifywait”的命令?

Posted

技术标签:

【中文标题】Mac 上是不是有类似“watch”或“inotifywait”的命令?【英文标题】:Is there a command like "watch" or "inotifywait" on the Mac?Mac 上是否有类似“watch”或“inotifywait”的命令? 【发布时间】:2010-12-03 16:43:51 【问题描述】:

我想在我的 Mac (Snow Leopard) 上查看一个文件夹,然后执行一个脚本(给它刚刚移动到文件夹中的文件名(作为参数... x.sh "filename"))。

我有一个全部用 bash (x.sh) 编写的脚本,它将在输入 $1 上移动一些文件和其他东西我只需要 OSX 在将新文件/文件夹移动/创建到目录时给我文件名.

有这样的命令吗?

【问题讨论】:

你应该问一下 DropBox 是如何做到的,因为他们大概尝试了所有可用的选项。 @JeffBurdges 我不太确定这会是一件容易的事。但是,在浏览了 Apple 的 FSEvents Reference 之后,我想说,如果 Dropbox 不使用它,那将是非常愚蠢的。下面作为答案提供的fswatch util 实际上确实使用了这种方法。 【参考方案1】:

fswatch

fswatch 是一个使用 Mac OS X FSEvents API 监控目录的小程序。 当收到有关对该目录的任何更改的事件时,指定的 shell命令由/bin/bash执行

如果您使用的是 GNU/Linux, inotifywatch(部分 inotify-tools 包在大多数发行版上)提供类似的 功能。

更新:fswatch 现在可以在许多平台上使用,包括 BSD、Debian 和 Windows。

语法/一个简单的例子

可以观察多个路径的新方法 - 对于1.x 及更高版本

fswatch -o ~/path/to/watch | xargs -n1 -I ~/script/to/run/when/files/change.sh

注意:如果不是-I-o 输出的数字将被添加到xargs 命令的末尾。如果您确实选择使用该号码,请将 放在您的命令中的任何位置。

版本 0.x 的旧方法:

fswatch ~/path/to/watch ~/script/to/run/when/files/change.sh

使用 Homebrew 安装

截至 2013 年 9 月 12 日,它已重新添加到 homebrew - 耶!因此,更新您的公式列表 (brew update),然后您需要做的就是:

brew install fswatch

不使用 Homebrew 安装

Terminal.app中输入这些命令

cd /tmp
git clone https://github.com/alandipert/fswatch
cd fswatch/
make
cp fswatch /usr/local/bin/fswatch

如果您的系统上没有c 编译器,您可能需要安装 Xcode 或 Xcode 命令行工具 - 两者都是免费的。但是,如果是这种情况,您可能应该只使用check out homebrew。

fswatch 1.x 版的附加选项

Usage:
fswatch [OPTION] ... path ...

Options:
 -0, --print0          Use the ASCII NUL character (0) as line separator.
 -1, --one-event       Exit fsw after the first set of events is received.
 -e, --exclude=REGEX   Exclude paths matching REGEX.
 -E, --extended        Use exended regular expressions.
 -f, --format-time     Print the event time using the specified format.
 -h, --help            Show this message.
 -i, --insensitive     Use case insensitive regular expressions.
 -k, --kqueue          Use the kqueue monitor.
 -l, --latency=DOUBLE  Set the latency.
 -L, --follow-links    Follow symbolic links.
 -n, --numeric         Print a numeric event mask.
 -o, --one-per-batch   Print a single message with the number of change events.
                       in the current batch.
 -p, --poll            Use the poll monitor.
 -r, --recursive       Recurse subdirectories.
 -t, --timestamp       Print the event timestamp.
 -u, --utc-time        Print the event time as UTC time.
 -v, --verbose         Print verbose output.
 -x, --event-flags     Print the event flags.

See the man page for more information.

【讨论】:

您的说明或在没有自制软件的情况下安装似乎不再起作用。 make 抛出关于找不到 makefile 的错误。幸运的是,fswatch 现在在 MacPorts 上,所以 sudo port install fswatch 对于我们这些使用 MacPorts 而不是 Homebrew 的人来说有效。 如果您使用带有静态参数的命令(例如,我在 src 上运行单元测试并测试更改),这可能不适合您。这个问题 (***.com/questions/25689589/…) 是我需要的第二个问题。 我听到你的声音:fswatch ./ | xargs -I cp ~/Dropbox/backup/latest/ fswatch 优于 entr 或 when_changed 等工具,后者在处理 .git 目录时存在一些错误。 fswatch 更专业。简单地说,你只需fswatch . 将监视当前目录。 我建议fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I [your command]-0 用于NULL。这个对我有用,可以减少编译【参考方案2】:

您可以为此目的使用launchd。 Launchd 可以配置为在修改文件路径时自动启动程序。

例如,当我的用户帐户的桌面文件夹被修改时,以下launchd config plist 将启动程序/usr/bin/logger

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>logger</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/logger</string>
        <string>path modified</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/sakra/Desktop/</string>
    </array>
</dict>
</plist>

要激活配置 plist,请将其作为“logger.plist”保存到库文件夹中的 LaunchAgents 文件夹中。

然后您可以在 shell 中使用命令 launchctl 通过运行来激活 logger.plist:

$ launchctl load ~/Library/LaunchAgents/logger.plist

现在正在监视桌面文件夹。每次更改时,您都应该在 system.log 中看到输出(使用 Console.app)。 要停用 logger.plist,请运行:

$ launchctl unload ~/Library/LaunchAgents/logger.plist

上面的配置文件使用了WatchPaths 选项。或者,您也可以使用 QueueDirectories 选项。有关详细信息,请参阅 launchd 手册页。

【讨论】:

有没有办法让它监控文件内容和文件路径的变化? 我不这么认为。为此,您可以使用opensnoop。 我让它工作了,但是当我用我的 Bash 脚本切换 /usr/bin/logger 并删除了 "&lt;string&gt;path modified&lt;/strong&gt;" 条目时,我找不到任何方法让我的 bash 脚本知道哪个文件在我的桌面被修改了——只是事件发生了。我尝试查看$0$1,但只得到了脚本名称本身,并注意到传递给它。 另外,这个东西一旦检测到变化就会进入循环,而不是在检测到变化时才启动(和停止)?我宁愿它按需工作,而不是一直循环运行告诉我,例如,2 天前,我的桌面上发生了一些变化,一遍又一遍地写在日志中。那么,我们需要在这个 plist 中使用某种间隔选项吗? 伟大的工作和解释【参考方案3】:

Facebook 的watchman,可通过 Homebrew 获得,看起来也不错。它还支持过滤:

这两行在源目录上建立一个监视,然后设置 启动一个名为“buildme”的触发器,它将运行一个名为“minify-css”的工具 每当更改 CSS 文件时。该工具将传递一个列表 更改了文件名。

$ watchman watch ~/src

$ watchman -- trigger ~/src buildme '*.css' -- minify-css

注意路径必须是绝对的。

【讨论】:

这是迄今为止最好的工具。 这是一个非常不错的小程序:文档很棒,它不会打开无限循环(fswatch 似乎就是这样做的)并且它会记住您在重启后创建的手表,并且自动再次启动它们。 @BentOnCoding 你能详细说明你是如何得出这个结论的吗? 我对各种解决方案进行了大量研究。该功能非常强大,并且始终如一地工作。【参考方案4】:

您可能想看看(也许扩展)我的小工具kqwait。目前它只是坐在那里等待单个文件上的写入事件,但kqueue 架构允许分层事件堆叠......

【讨论】:

目前在山狮上工作。非常好! 所以这真的很棒。我遇到了fswatch 的一个小问题(这也很好,因为它是如此轻量级的包装,它也可以被修改以做我确定的正确的事情)当运行像git status 这样的东西时它会触发(这实际上每次在我的机器上呈现 zsh 提示时都会运行...)实际上通过创建一个无休止的反馈循环来搞砸我拥有的这个精心制作的脚本。但是,kqwait 会提供有关更改文件的信息,并且不会被git status 触发。我确实需要它在写入时触发。 $ brew install kqwait &amp;&amp; while true; do kqwait doc/my_file.md; make; done 简单,在 Mojave 上就像一个魅力(可能在任何未来的 Mac OS 上)。【参考方案5】:

watchdog 是一个用于监视文件/目录的跨平台python API,它具有内置的“技巧”工具,允许您在事件发生时(包括新添加的文件、删除的文件和更改的文件)。

【讨论】:

【参考方案6】:

这只是提到entr 作为 OSX 上的替代方案,用于在文件更改时运行任意命令。我觉得它简单实用。

brew install entr 在 macos 上 apt install entr 在 Debian/Ubuntu 上

【讨论】:

【参考方案7】:

这是使用sschober 的tool 的单行代码。

$ while true; do kqwait ./file-to-watch.js; script-to-execute.sh; done

【讨论】:

$ brew install kqwait【参考方案8】:

Apple OSX Folder Actions 允许您根据对文件夹执行的操作自动执行任务。

【讨论】:

是的,我知道,我试过几次,都没有成功,你能举个例子吗? 这是一个链接,不是答案【参考方案9】:

编辑: fsw 已合并到 fswatch。在这个答案中,任何对fsw 的引用现在都应该是fswatch

我用 C++ 编写了一个名为 fswfswatch 替代品,它具有多项改进:

这是一个 GNU 构建系统项目,可以在任何受支持的平台 (OS X v. >= 10.6) 上构建

./configure && make && sudo make install

多个路径可以作为不同的参数传递:

fsw file-0 ... file-n 

它转储包含所有事件信息的详细记录,例如:

Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 

它的输出很容易解析,因此fsw 的输出可以通过管道传送到另一个进程。

可以使用-l, --latency 自定义延迟。 可以用-n, --numeric 编写数字事件标志而不是文本标志。 可以使用strftime 格式字符串和-t, --time-format 自定义时间格式。 时间可以是机器的本地时间(默认)或UTC时间-u, --utc-time

获取 fsw:

fsw 是hosted on GitHub,可以通过克隆其存储库获得:

    git clone https://github.com/emcrisostomo/fsw

安装 fsw:

fsw可以使用以下命令安装:

    ./configure && make && sudo make install

更多信息:

我还写了一篇介绍性的blog post,您可以在其中找到一些关于fsw 工作原理的示例。

【讨论】:

【参考方案10】:

fswatch 我的 fork 提供了 inotifywait -m 的功能,但对解析友好的输出略少(不用等待,更多!我在使用 inotifywait...的 Linux 上遇到的麻烦更多。)

它是对原始 fswatch 的改进,因为它通过 STDOUT 发送更改文件的实际路径,而不是要求您提供它派生的程序。

作为我用来自动化操作的一系列可怕 bash 脚本的基础,它非常稳固。

(这是题外话)另一方面,Linux 上的inotifywait 需要大量的杂项,我仍然没有找到管理它的好方法,尽管我认为一些基于node.js 可能是票。

【讨论】:

对,fswatch 的分支。 that 在 Homebrew 上吗? 答案是否定的;但他们是working on it。要快速安装,只需brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb【参考方案11】:

我有一个 GIST,用法很简单

watchfiles <cmd> <paths...>

为了说明,每次file1file2发生变化时,以下命令都会回显Hello World;并且默认间隔检查是 1 秒

watchfiles 'echo Hello World' /path/to/file1 /path/to/file2 

如果我想每 5 秒检查一次,我可以使用 -t 标志

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
-v 启用显示调试信息的verbose 模式 -q 使watchfiles 安静地执行(# 将被显示,以便用户可以看到程序正在执行) -qq 使 watchfiles 完全安静地执行 -h 显示帮助和用法

https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55

【讨论】:

【参考方案12】:

我最终为 macOS 做了这个。我敢肯定这在很多方面都很糟糕:

#!/bin/sh
# watchAndRun
if [ $# -ne 2 ]; then
    echo "Use like this:"
    echo "   $0 filename-to-watch command-to-run"
    exit 1
fi
if which fswatch >/dev/null; then
    echo "Watching $1 and will run $2"
    while true; do fswatch --one-event $1 >/dev/null && $2; done
else
    echo "You might need to run: brew install fswatch"
fi

【讨论】:

没有一段时间我无法弄清楚 fswatch 语法。这很烦人,使脚本难以停止。【参考方案13】:

如果你想使用 NodeJS,你可以使用一个名为chokidar(实际上是chokidar-cli)的包来观看,然后使用rsync(Mac 自带):

rsync 命令:

$ rsync -avz --exclude 'some-file' --exclude 'some-dir' './' '/my/destination'

Chokidar cli(通过 npm 全局安装):

chokidar \"**/*\" -c \"your-rsync-command-above\"

【讨论】:

【参考方案14】:

sudo fs_usage -f 文件系统 | grep “有趣的事情”?

【讨论】:

这是一个问题还是一个答案? 欢迎来到 Stack Overflow!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高帖子的质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 感谢您发布无需安装第三方软件直接在终端上运行的唯一选项。【参考方案15】:

对于没有watch 命令且希望每 3 秒执行一次命令的用户,这里有一个简单的单行替代方案:

while :; do your-command; sleep 3; done

这是一个无限循环,基本上和下面做的一样:

watch -n3 your-command

【讨论】:

这与使用监听文件系统事件的库不同。如果在您的示例中,your-command 执行磁盘 I/O,那么这是 保证 磁盘每 3 秒读/写一次 - 或每 小时 10,800 次。 通过使用文件系统事件您可以保证 I/O(和其他昂贵的操作)仅在您更改文件时发生(通常每小时只有几次。) 正确,值得考虑。我通常需要 watch 暂时的时间来查看某事在做什么。我不会将我提到的技术用于生产应用程序或类似的东西。例如,我想查看dd 的进度,而我的技术使它成为可能(酌情替换your-command 以向dd 发送适当的信号)。

以上是关于Mac 上是不是有类似“watch”或“inotifywait”的命令?的主要内容,如果未能解决你的问题,请参考以下文章

Mac iOS Mac Watch 应用和游戏编程开发工具推荐

Apple Watch 是不是被 RFID 读取器检测到?

如何在Mac上安装Apple Watch屏幕保护程序

Mac OSX Cocoa App:是不是可以让您的 App 使用 san francisco 字体(用于 Apple Watch 的字体)?

UNUserNotification 是不是可以选择仅在 Apple Watch 上显示通知?

Mac OS X 是不是有 virt-manager 替代品? [关闭]