我想在我的 Mac 上查看一个文件夹,然后执行一个 bash 脚本,将刚刚移动到或在监视目录中创建的任何文件/文件夹的名称传递给它。
fswatch
实用程序实际上确实使用了这种方法。
fswatch
fswatch
是一个使用 Mac OS X FSEvents API 监控目录的小程序。当收到有关对该目录的任何更改的事件时,/bin/bash
将执行指定的 shell 命令
如果您使用的是 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.
您可以为此目的使用 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 手册页。
/usr/bin/logger
并删除 "<string>path modified</strong>"
条目时,我找不到任何方法让我的 bash 脚本知道我桌面上的哪个文件被修改了 - 就是这样事件发生。我尝试查看 $0
、$1
并且只获得了脚本名称本身,并注意到传递给它。
Facebook 的 watchman 可通过 Homebrew 获得,看起来也不错。它还支持过滤:
这两行在源目录上建立了一个监视,然后设置了一个名为“buildme”的触发器,该触发器将在 CSS 文件更改时运行一个名为“minify-css”的工具。该工具将传递已更改文件名的列表。 $ watchman watch ~/src $ watchman -- 触发 ~/src buildme '*.css' -- minify-css
请注意,路径必须是绝对的。
您可能想看看(并可能扩展)我的小工具 kqwait
。目前它只是坐在那里等待单个文件上的写入事件,但 kqueue 架构允许分层事件堆叠......
fswatch
时遇到了一个小问题(这也很好,因为它是一个轻量级的包装器,我确信它也可以被修改以做正确的事情)在运行 git status
之类的东西时它会触发(其中实际上每次在我的机器上呈现 zsh 提示时都会运行...)这实际上通过创建一个无休止的反馈循环来搞砸我拥有的这个精心制作的脚本。但是,kqwait 提供有关已更改文件的信息,并且不会被 git status
触发。我确实需要它在写入时触发。
$ brew install kqwait && while true; do kqwait doc/my_file.md; make; done
watchdog 是一个用于监视文件/目录的跨平台 python API,它具有内置的“技巧”工具,允许您在事件发生时触发操作(包括 shell 命令)(包括新添加的文件、删除的文件和更改的文件) .
这只是提到 entr 作为 OSX 上的替代方案,以在文件更改时运行任意命令。我觉得它简单而有用。
在 macOS 上 brew install entr
在 Debian/Ubuntu 上 apt install entr
编辑: fsw
已合并到 fswatch
。在此答案中,对 fsw
的任何引用现在都应为 fswatch
。
我用 C++ 编写了一个名为 fsw
的 fswatch
替代品,它具有多项改进:
这是一个 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 写入数字事件标志而不是文本标志。
可以使用带有 -t、--time-format 的 strftime 格式字符串自定义时间格式。
时间可以是机器的本地时间(默认情况下)或带有 -u、--utc-time 的 UTC 时间。
获取 fsw:
fsw
是 hosted on GitHub,可以通过克隆其存储库获得:
git clone https://github.com/emcrisostomo/fsw
安装 fsw:
fsw
可以使用以下命令安装:
./configure && make && sudo make install
更多信息:
我还写了一个介绍性的 blog post,您可以在其中找到几个有关 fsw
工作原理的示例。
我的 fswatch 分支提供了 inotifywait -m
的功能,但对解析友好的输出略少(不用等待,更多!我在使用 inotifywait
的 Linux 上遇到的麻烦更多...)。
它是对原始 fswatch
的改进,因为它通过 STDOUT 发送更改文件的实际路径,而不是要求您提供它派生的程序。
作为我用来自动化操作的一系列可怕 bash 脚本的基础,它一直坚如磐石。
(这是题外话)另一方面,Linux 上的 inotifywait
需要大量的杂项,我仍然没有找到管理它的好方法,尽管我认为基于 {2 } 可能是票。
brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
我有一个 GIST,用法很简单
watchfiles <cmd> <paths...>
为了说明,以下命令将在每次 file1
OR file2
更改时回显 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 启用显示调试信息的详细模式
-q 让监视文件安静地执行(将显示#,以便用户可以看到程序正在执行)
-qq 使监视文件完全安静地执行
-h 显示帮助和用法
https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55
我最终为 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
如果您想使用 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\"
sudo fs_usage -f 文件系统 | grep“有趣的事情”?
对于没有 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
发送适当的信号)。
make
引发关于找不到 makefile 的错误。幸运的是,fswatch 现在在 MacPorts 上,所以sudo port install fswatch
对于我们这些使用 MacPorts 而不是 Homebrew 的人有效。fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
fswatch .
将监视当前目录。fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]
和-0
。这个对我有用,可以减少编译