Jacky's blog
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • Android
  • Web
  • Server
  • Python
  • iOS
  • Java
  • Vue
  • 计算机基础
  • AI
  • 全部工具
  • CLI 工具
  • 编辑器
  • 开发工具
  • 构建工具
  • 版本控制
  • 调试工具
  • 网络工具
  • 个人成长
  • 博客
  • 分类
  • 标签
  • 归档
收藏
GitHub (opens new window)
  • 开发工具

  • 构建工具

  • 版本控制

  • 容器

  • 调试工具

  • 测试工具

  • CLI 工具

    • tmux
    • oh-my-zsh
    • ripgrep 高性能文本搜索工具使用指南
    • awk
    • sed
    • xargs
    • fzf
    • fd
    • raycast
    • VisiData 终极生存指南(vd)
    • yq
    • direnv
      • 1. 什么是 direnv
      • 2. 安装
      • 3. 快速开始
        • 3.1 配置 shell hook
        • 3.2 创建 .envrc
        • 3.3 批准 .envrc
      • 4. 常用命令
      • 5. 常用场景
        • 5.1 Node.js 版本管理
        • 5.2 Python 虚拟环境
        • 5.3 项目环境变量
        • 5.4 扩展 PATH
        • 5.5 加载 .env 文件
        • 5.6 多环境切换
      • 6. 标准库(stdlib)
        • 6.1 路径管理
        • 6.2 环境变量
        • 6.3 语言版本管理(stdlib 实际仅支持以下 use_*)
        • 6.4 虚拟环境 / 项目布局
        • 6.5 其他实用函数
      • 7. 安全机制
        • 7.1 为什么需要 allow
        • 7.2 查看已批准的目录
        • 7.3 全局白名单
      • 8. 与其他工具集成
        • 8.1 与 nvm 集成
        • 8.2 与 pyenv 集成
        • 8.3 与 asdf 集成
        • 8.4 与 .env 文件集成
        • 8.5 与 VS Code 集成
      • 9. 常见问题
        • 9.1 修改 .envrc 后不生效
        • 9.2 进入目录没有反应
        • 9.3 环境变量没有卸载
        • 9.4 如何调试 .envrc
        • 9.5 .envrc 应该提交到 git 吗
      • 10. 实用技巧
        • 10.1 全局配置
        • 10.2 监视文件变化
        • 10.3 条件加载
        • 10.4 项目根目录向上查找
      • 参考链接
    • ln 软链接/硬链接使用指南
    • watch 周期监控使用指南
    • osascript
  • 网络工具

  • 编辑器

  • 设计工具

  • 多媒体

  • 包管理

  • 平台工具

  • tools
  • cli_tools
Jacky
2026-09-09
目录

direnv

direnv 是一个 shell 环境管理工具,能够在进入目录时自动加载项目特定的环境变量,离开目录时自动卸载。支持 bash、zsh、fish、tcsh 等多种 shell。 本文基于 direnv 2.37.1 实测验证(stdlib 函数清单均来自 direnv stdlib 输出)。

# 1. 什么是 direnv

每个项目可能需要不同的环境变量(Node 版本、Python 虚拟环境、API Key、PATH 扩展等)。direnv 通过在项目根目录放置 .envrc 文件,实现:

  • 进入目录:自动加载 .envrc 中定义的环境变量
  • 离开目录:自动恢复之前的环境,不污染全局 shell
  • 安全机制:.envrc 修改后需手动 direnv allow 批准,防止恶意代码自动执行

# 2. 安装

# macOS
brew install direnv

# Ubuntu/Debian
sudo apt-get install direnv

# Arch Linux
sudo pacman -S direnv
1
2
3
4
5
6
7
8

# 3. 快速开始

# 3.1 配置 shell hook

在 shell 配置文件中添加 hook(根据使用的 shell 选择):

zsh(~/.zshrc)

eval "$(direnv hook zsh)"
1

bash(~/.bashrc 或 ~/.bash_profile)

eval "$(direnv hook bash)"
1

fish(~/.config/fish/config.fish)

direnv hook fish | source
1

配置后重启终端或 source ~/.zshrc 生效。

# 3.2 创建 .envrc

在项目根目录创建 .envrc 文件:

# 项目根目录
cd my-project

# 创建 .envrc
echo 'export NODE_ENV=development' > .envrc
1
2
3
4
5

此时会看到提示:

direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
1

# 3.3 批准 .envrc

direnv allow
1

批准后,进入目录时自动加载环境变量:

direnv: export +NODE_ENV
1

离开目录时自动卸载:

direnv: export -NODE_ENV
1

# 4. 常用命令

命令 说明
direnv allow [路径] 批准当前目录(或指定目录)的 .envrc
direnv deny [路径] 拒绝/撤销 .envrc 的批准
direnv reload 重新加载当前目录的 .envrc
direnv status 查看 direnv 状态(哪些目录已批准、当前加载情况)
direnv edit [路径] 编辑 .envrc(保存后自动 allow)
direnv exec <目录> <命令> 在指定目录的环境下执行命令(不切换目录)
direnv export <shell> 导出当前目录的环境变量(用于调试)
direnv version 查看版本

# 5. 常用场景

# 5.1 Node.js 版本管理

配合 nvm 使用:

# .envrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
nvm use v18.20.7
1
2
3
4

或使用标准库的 use node(需先指定版本目录,详见 §8.1):

# .envrc
export NODE_VERSIONS="$HOME/.nvm/versions/node"
export NODE_VERSION_PREFIX=v
use node 18.20.7
1
2
3
4

# 5.2 Python 虚拟环境

# .envrc
# 自动创建并激活虚拟环境(Python ≥3.3 用内置 venv;<3.3 需已安装 virtualenv)
layout python

# 或明确使用 python3
layout python3
1
2
3
4
5
6

layout python 会自动:

  • 在 direnv 管理的缓存目录(direnv_layout_dir)创建虚拟环境(如果不存在)
  • 激活虚拟环境
  • 离开目录时自动 deactivate

⚠️ stdlib 中没有 layout python-venv 这个函数(网上旧文常见此写法),实际可用的是 layout python / layout python3 / layout pyenv / layout pipenv / layout anaconda。

# 5.3 项目环境变量

# .envrc
export API_KEY="your-api-key-here"
export DATABASE_URL="postgres://localhost:5432/mydb"
export DEBUG=true
1
2
3
4

# 5.4 扩展 PATH

将项目本地的 bin/ 目录加入 PATH:

# .envrc
PATH_add bin
1
2

或使用标准库:

# .envrc
path_add bin
1
2

# 5.5 加载 .env 文件

如果项目使用 .env 文件管理环境变量:

# .envrc
dotenv
1
2

dotenv 会自动加载当前目录的 .env 文件。也可以指定文件名:

dotenv .env.development
1

# 5.6 多环境切换

# .envrc
# 根据当前 git 分支加载不同环境(on_git_branch 是 stdlib 内置函数)
if on_git_branch main; then
  export NODE_ENV=production
else
  export NODE_ENV=development
fi
1
2
3
4
5
6
7

# 6. 标准库(stdlib)

direnv 内置了一组实用函数,可在 .envrc 中直接使用:

# 6.1 路径管理

函数 说明
PATH_add <路径> 将路径加入 PATH(去重,规范写法)
path_add <路径> 同上(旧写法别名)
PATH_rm <路径> 从 PATH 中移除
MANPATH_add <路径> 将路径加入 MANPATH(注意大写)

# 6.2 环境变量

函数 说明
export <变量>=<值> 设置环境变量(标准 shell 语法)
unset <变量> 取消环境变量
set -a / set +a 自动 export 所有变量

# 6.3 语言版本管理(stdlib 实际仅支持以下 use_*)

函数 说明
use node <版本> 切换 Node 版本(需设置 $NODE_VERSIONS 指向版本目录,见 §8.1)
use nodenv <版本> 通过 nodenv 切换 Node 版本
use rbenv <版本> 通过 rbenv 切换 Ruby 版本
use julia <版本> 切换 Julia 版本
use vim <版本> 切换 Vim 版本
use nix / use flake / use guix 加载 Nix / Nix flake / Guix 环境

⚠️ stdlib 没有 use python / use go / use java / use rust / use ruby / use asdf(网上旧文常见这些写法,均不存在)。Python 版本用 layout pyenv <版本>;asdf 集成见 §8.3。

# 6.4 虚拟环境 / 项目布局

函数 说明
layout python 创建并激活 Python 虚拟环境(≥3.3 内置 venv;❤️.3 需 virtualenv)
layout python3 同上,明确使用 python3
layout pyenv <版本> 通过 pyenv 切换 Python 版本并激活虚拟环境
layout pipenv 激活 Pipenv 环境
layout anaconda 激活 Anaconda 环境
layout node 初始化 Node 项目环境(设置 NODE_PATH)
layout ruby 初始化 Ruby 项目环境
layout go 初始化 Go 项目环境(设置 GOPATH)
layout perl / layout php / layout julia / layout opam 对应语言的项目布局

# 6.5 其他实用函数

函数 说明
dotenv [文件] 加载 .env 文件
dotenv_if_exists [文件] 文件存在才加载
source_env <文件> 加载另一个 envrc 文件
source_env_if_exists <文件> 如果文件存在则加载
source_up 向上查找并加载父级 .envrc(monorepo 常用)
watch_file <文件> 监视文件变化,变化时自动 reload
watch_dir <目录> 监视整个目录变化
has <命令> 检查命令是否存在(返回 0/1)
on_git_branch <分支> 当前 git 分支匹配时返回真(条件加载用)
join_args <args> 将参数拼接为字符串
strict_env / unstrict_env 开启/关闭严格模式(不继承未显式声明的变量)
load_prefix <路径> 加载交叉编译前缀环境
direnv_layout_dir 输出 direnv 缓存目录路径(虚拟环境等落盘处)

# 7. 安全机制

direnv 的安全设计是其核心特性之一:

# 7.1 为什么需要 allow

.envrc 是一个可执行的 shell 脚本,如果自动加载可能导致恶意代码执行(例如克隆一个包含恶意 .envrc 的项目后,进入目录就自动执行)。

因此 direnv 要求:

  • 首次进入目录:必须手动 direnv allow
  • .envrc 修改后:之前的 allow 失效,需要重新 direnv allow
  • 可以随时 direnv deny 撤销批准

# 7.2 查看已批准的目录

direnv status
1

输出示例:

direnv exec path /opt/homebrew/bin/direnv
DIRENV_CONFIG ~/.config/direnv
bash_path: /bin/bash
...

Loaded RC path: ~/code/my-project/.envrc
Allowed RC path: ~/code/my-project/.envrc
1
2
3
4
5
6
7

# 7.3 全局白名单

如果信任某个目录下的所有项目,可以在全局配置中设置白名单:

# ~/.config/direnv/direnv.toml
[whitelist]
prefix = ["/path/to/trusted/projects"]
1
2
3

# 8. 与其他工具集成

# 8.1 与 nvm 集成

nvm 没有官方 stdlib 函数,推荐手动加载(见 §5.1 的写法):

# .envrc
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
nvm use v18.20.7
1
2
3
4

use node 是另一条路线:它不会自动查找 nvm,而是读取 $NODE_VERSIONS 指向的版本目录(可指向 nvm/nodenv 的 versions 目录):

# .envrc
export NODE_VERSIONS="$HOME/.nvm/versions/node"
export NODE_VERSION_PREFIX=v
use node 18.20.7
1
2
3
4

未设置 $NODE_VERSIONS 时会报错:You must specify a $NODE_VERSIONS environment variable。

# 8.2 与 pyenv 集成

stdlib 没有 use python,pyenv 用 layout pyenv:

# .envrc
layout pyenv 3.11.4
1
2

# 8.3 与 asdf 集成

use asdf 不是 stdlib 内置函数,需先安装 asdf 的 direnv 插件(asdf-direnv):

asdf plugin add direnv
1
# .envrc
use asdf
1
2

安装后 use asdf 会自动读取项目根目录的 .tool-versions 文件。

# 8.4 与 .env 文件集成

很多项目(尤其是 Node.js)使用 .env 文件管理环境变量:

# .envrc
dotenv
1
2

.env 文件示例:

DATABASE_URL=postgres://localhost:5432/mydb
API_KEY=secret-key
DEBUG=true
1
2
3

# 8.5 与 VS Code 集成

在 VS Code 中,direnv 加载的环境变量不会自动传递给 VS Code 的终端和调试器。可以安装 direnv 扩展,或在 .vscode/settings.json 中配置:

{
  "terminal.integrated.env.osx": {
    "DIRENV_LOG_FORMAT": ""
  }
}
1
2
3
4
5

# 9. 常见问题

# 9.1 修改 .envrc 后不生效

修改 .envrc 后,direnv 会自动检测到变化并提示重新 allow:

direnv: error .envrc has changed. Run `direnv allow` to approve its content.
1

运行 direnv allow 或 direnv reload 即可。

也可以使用 direnv edit 编辑,保存后自动 allow:

direnv edit
1

# 9.2 进入目录没有反应

检查:

  1. shell hook 是否配置:eval "$(direnv hook zsh)"
  2. .envrc 是否存在于当前目录
  3. 是否已经 direnv allow
  4. direnv 版本是否过旧:direnv version

# 9.3 环境变量没有卸载

direnv 通过记录进入目录前的环境状态,在离开时恢复。如果环境变量没有正确卸载,可能是因为 .envrc 中使用了不规范的方式修改变量。

正确做法:使用 direnv 标准库函数

# 正确
path_add bin
export MY_VAR=value

# 不推荐(可能导致卸载异常)
export PATH="$PWD/bin:$PATH"
1
2
3
4
5
6

# 9.4 如何调试 .envrc

# 查看 direnv 会执行什么
direnv export bash

# 在指定目录环境下执行命令
direnv exec /path/to/project env

# 详细日志
DIRENV_DEBUG=1 direnv reload
1
2
3
4
5
6
7
8

# 9.5 .envrc 应该提交到 git 吗

取决于内容:

  • 如果 .envrc 只包含公开的环境配置(如 Node 版本、PATH 扩展),可以提交
  • 如果包含敏感信息(API Key、密码),不要提交,应加入 .gitignore,并提供 .envrc.example 模板

推荐做法:

# .gitignore
.envrc
.env
.env.local

# 提交模板
.envrc.example
1
2
3
4
5
6
7

# 10. 实用技巧

# 10.1 全局配置

创建全局 direnv 配置,所有项目共享:

# ~/.config/direnv/direnvrc
# 这里定义的函数在所有 .envrc 中可用

my_custom_function() {
  echo "Hello from global direnv config"
}
1
2
3
4
5
6

# 10.2 监视文件变化

如果 .envrc 依赖其他文件(如 .nvmrc、.tool-versions),可以监视这些文件:

# .envrc
watch_file .nvmrc
export NODE_VERSIONS="$HOME/.nvm/versions/node"
export NODE_VERSION_PREFIX=v
use node $(cat .nvmrc)
1
2
3
4
5

当 .nvmrc 变化时,direnv 会自动 reload。

# 10.3 条件加载

# .envrc
# 只在 macOS 上设置某些变量
if [ "$(uname)" = "Darwin" ]; then
  export MACOS_SPECIFIC_VAR=value
fi

# 只在命令存在时加载
if has docker; then
  export DOCKER_BUILDKIT=1
fi
1
2
3
4
5
6
7
8
9
10

# 10.4 项目根目录向上查找

direnv 会从当前目录向上查找 .envrc,直到找到为止。这意味着在项目的子目录中也能正确加载环境变量。

如果子目录有自己的 .envrc,会覆盖父目录的配置。

# 参考链接

  • direnv 官方网站 (opens new window)
  • direnv GitHub (opens new window)
  • direnv 标准库文档 (opens new window)
  • direnv 配置文档 (opens new window)
#direnv#Shell#tool#cli
上次更新: 2026/10/18, 22:14:48
yq
ln 软链接/硬链接使用指南

← yq ln 软链接/硬链接使用指南→

最近更新
01
Codex 使用与会话管理指南
10-17
02
Tailscale 入门:让自己的设备跨网络互联
10-15
03
GitHub CLI(gh)工作流与 CI 排查
10-08
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式