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, 跨平台