entr

> entr — 文件一变,命令就跑,告别手动重启和重复劳动。 --- 兄弟们,今天聊个能让你少掉点头发的命令行小工具——`entr`。 先说说痛点。你写代码的时候,是不是经常这样:改完一个文件,切到终端,Ctrl+C,上下键找回上次的命令,回车,等编译/测试/重启服务……一天重复几十次。要是碰上改CSS、改配置文件这种高频操作,手都能抽筋。更烦的是,有时候忘了重启,拿旧状态调试半天,最后发现是缓存没刷新,心态直接炸裂。 `entr`就是干这个的。它的核心逻辑就一句话:**监控一组文件,一旦有变化,就执行你指定的命令**。听起来简单,但用好了,能把你从“手动触发”的泥潭里拽出来,进入“改完即生效”的自动化状态。 ### 它是谁?解决什么问题? `entr`是一个Unix命令行工具,全称大概是“event notifier with a twist”(我瞎猜的,但意思对)。它不依赖某个特定语言或框架,纯粹站在文件系统事件之上。你告诉它“盯着这些文件”,再告诉它“变了就干这个”,剩下的交给它。 它能解决的问题: - **开发时自动重启服务**(Node、Python、Go、Ruby……啥都行) - **自动跑测试**(保存代码立刻看到红绿) - **自动构建前端资源**(改完SCSS自动编译成CSS) - **自动同步文件**(比如改完配置自动rsync到服务器) - **任何你不想手动重复的命令** 相比`nodemon`、`watchman`这些,`entr`的优势在于:**极简、无依赖、跨平台**(Linux、macOS、BSD都能跑,Windows用WSL)。它不挑语言,不绑框架,就是一个纯粹的“触发器”。 ### 怎么装? 官网地址在这里:[https://eradman.com/entrproject/](https://eradman.com/entrproject/) 安装方式很随意,看你的系统: **macOS(用Homebrew):** ```bash brew install entr ``` **Debian/Ubuntu:** ```bash sudo apt install entr ``` **Arch Linux:** ```bash sudo pacman -S entr ``` **FreeBSD:** ```bash pkg install entr ``` 要是你系统太老没包,直接去官网下源码编译,也就十几秒的事。 ### 基础使用:先跑起来 用法核心就两个参数:`-d`(监控目录变化)和管道输入文件列表。最经典的姿势: ```bash ls *.py | entr python main.py ``` 意思是:把当前目录所有`.py`文件喂给`entr`,一旦其中任何一个文件有改动,就杀掉正在运行的`python main.py`,重新启动。 注意:`entr`默认是**先执行一次命令**,然后再开始监控。所以第一次运行就会启动你的程序,后面每次改文件都会重启。 **更实用的重启服务器例子(Node.js):** ```bash ls server.js routes/*.js | entr -r node server.js ``` `-r`参数表示`--restart`,它会先发送SIGTERM给当前进程,再重新执行命令。比直接`pkill`干净。 **自动跑测试:** ```bash ls src/*.js test/*.js | entr npm test ``` 保存一下,测试立刻跑起来,红绿反馈极快。 **监控目录变化(新增/删除文件):** 如果你新增了一个文件,`ls *.py`这种固定列表是抓不到的。这时候用`-d`: ```bash find . -name '*.py' | entr -d python main.py ``` `-d`让`entr`监控文件所在目录,如果有新文件匹配(或文件被删),也会触发。注意:配合`find`用更稳。 ### 进阶技巧:玩出花来 **1. 用`-c`清屏,让输出干净点** 每次重启服务,终端里全是旧日志,烦不烦?加个`-c`: ```bash ls *.go | entr -c go run main.go ``` 每次触发前自动清屏,输出清爽多了。 **2. 结合`-p`(持久化)处理大量文件** 如果你监控的文件特别多(比如几千个),`entr`默认会重新扫描文件列表。加`-p`可以保留之前的文件列表,避免重复扫描,性能提升明显: ```bash find . -name '*.js' | entr -p npm run build ``` **3. 用`/`作为文件参数,监控整个目录(递归)** 不想用`find`?`entr`支持直接传目录,配合`-d`: ```bash entr -d sh -c 'make && ./run_tests' <<< './src/' ``` 这里用heredoc把目录路径传进去。但注意,这种方式会监控该目录下所有文件(包括二进制、隐藏文件),触发可能太频繁。建议还是`find`筛选扩展名。 **4. 排除特定文件(比如日志)** 用`!`前缀排除。比如监控所有`*.py`但忽略`__pycache__`下的: ```bash find . -name '*.py' ! -path './__pycache__/*' | entr -r python main.py ``` **5. 用`-s`执行shell命令,而不是单个程序** 有时候你想跑一串命令,比如“改完SCSS,先编译,再刷新浏览器”。用`-s`: ```bash ls src/*.scss | entr -s 'make css && livereload' ``` `-s`会把后面内容当字符串交给`sh -c`执行,灵活度拉满。 **6. 组合拳:自动部署到服务器** ```bash ls dist/ | entr -s 'rsync -avz dist/ user@server:/var/www/ && ssh user@server "systemctl reload nginx"' ``` 改完本地构建,自动同步,自动重载服务。一套带走。 **7. 配合`make`或`npm run`,实现“保存即构建”** ```bash ls src/ | entr -r make dev ``` 改完代码,不用手动按,自己就编译重启了。 ### 几个小坑提醒 - **别监控正在写入的文件**(比如数据库文件、日志文件),否则可能触发无限循环。用`find`排除掉。 - **`entr`默认不处理子进程的退出**,如果命令返回非零状态码,它可能还是会继续监控。但如果你用`-r`,它会等子进程退出再重启。如果子进程卡住,`entr`也会卡住。这时候可以配合`timeout`命令。 - **文件列表用`ls`还是`find`?** 如果文件数量少且稳定,`ls`够用。如果有嵌套目录或动态新增,用`find` + `-d`。 - **macOS上`-d`可能有点慢**,因为文件事件机制不同。如果遇到延迟,试试不用`-d`,用`find`定期扫描(但`entr`本身是事件驱动的,不扫描)。 ### 最后说点真心话 `entr`不是那种能让你发朋友圈炫耀的酷炫工具,但它就像一把趁手的螺丝刀——平时不起眼,一旦你用顺手了,就再也回不去了。它把“改代码”和“看结果”之间的那点摩擦降到了最低,让你更专注在写代码本身,而不是机械地切换窗口按回车。 我现在的习惯是:每个项目启动时,先写一个`dev.sh`脚本,里面就是一行`ls ... | entr -r ...`。以后每天开工,跑一下脚本,剩下的时间只需要专心改文件,终端自己会干活。 如果你还在手动重启服务、手动跑测试,强烈建议花两分钟装上`entr`,体验一把“改完即所见”的丝滑。真的,试一次你就回不去了。 --- **标签:** 文件变更触发, CLI, 跨平台