mcpField
D
direnv

direnv

github.com/julianobarbosa开发14119 次安装2 天前更新
代码仓库

关于 direnv

面向开发者的 direnv 指南,涵盖安装、配置与排错,用于管理项目级 shell 环境。内容包括 `.envrc` 模式、语言布局、安全机制和常见问题。

主要功能

  1. 01安装与 shell 钩子配置
  2. 02`.envrc` 配置与允许列表安全机制
  3. 03环境变量和标准库函数
  4. 04语言布局与 Nix 集成
  5. 05排错与配置实践

适用场景

  1. 01为 shell 配置 direnv
  2. 02设置项目级变量和路径
  3. 03加载语言或 Nix 环境
  4. 04排查环境加载问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/julianobarbosa/claude-code-skills --skill direnv

安装后在 Claude Code 中输入/direnv确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
installation.md
stdlib-functions.md
troubleshooting.md

详细介绍

direnv 技能

本技能提供有关使用 direnv 的全面指导,涵盖安装、配置、标准库函数以及按项目管理环境的最佳实践。

何时使用此技能

在以下情况下使用此技能:

  • 在 macOS 或 Linux 上安装和配置 direnv
  • 为项目创建或修改 .envrc 文件
  • 设置按项目配置的环境变量
  • 配置特定语言的布局(Python、Node.js、Ruby、Go、Perl)
  • 将 direnv 与 Nix 或 Nix Flakes 集成
  • 为团队管理密钥和环境配置
  • 排查环境加载问题
  • 创建自定义 direnv 扩展

核心概念

什么是 direnv?

direnv 是一种 shell 扩展,会根据当前目录加载和卸载环境变量。当你使用 cd 进入包含 .envrc 文件的目录时,direnv 会自动加载环境。离开该目录时,它会卸载所做的更改。

安全模型

direnv 使用基于允许列表的安全机制:

  • 新建或修改的 .envrc 文件必须通过 direnv allow 明确允许
  • 防止自动执行不可信脚本
  • 使用 direnv deny 撤销访问权限
工作原理
  1. Shell 钩子拦截目录切换
  2. 检查当前目录或父目录中是否存在 .envrc 文件
  3. 如果已允许,则在 bash 子 shell 中执行 .envrc
  4. 捕获导出的变量并将其应用到当前 shell

安装

macOS(Homebrew - 推荐)
brew install direnv
Linux
# Ubuntu/Debian
sudo apt install direnv

# Fedora
sudo dnf install direnv

# Arch
sudo pacman -S direnv

# Binary installer (any system)
curl -sfL https://direnv.net/install.sh | bash
验证安装
direnv version

Shell 配置

将钩子添加到 shell 的配置文件中。这是 direnv 正常运行的必要条件。

Zsh (~/.zshrc)
eval "$(direnv hook zsh)"

使用 Oh My Zsh 时:

plugins=(... direnv)
Bash (~/.bashrc)
eval "$(direnv hook bash)"

**重要:**放在 rvm、git-prompt 和其他会修改提示符的扩展之后。

Fish (~/.config/fish/config.fish)
direnv hook fish | source
配置完成后

重启 shell:

exec $SHELL

.envrc 文件基础知识

创建 .envrc
# In your project directory
touch .envrc

# Edit with your preferred editor
vim .envrc
基本语法
# Export environment variables
export NODE_ENV=development
export API_URL=http://localhost:3000
export DATABASE_URL=postgres://localhost/myapp

# The export keyword is required for direnv to capture variables
允许 .envrc
# Allow current directory
direnv allow

# Allow specific path
direnv allow /path/to/project

# Deny/revoke access
direnv deny

标准库函数

direnv 包含功能强大的标准库。请始终优先使用标准库函数,而不是手动导出变量。

PATH 管理
# Prepend to PATH (safer than manual export)
PATH_add bin
PATH_add node_modules/.bin
PATH_add scripts

# Add to arbitrary path-like variable
path_add PYTHONPATH lib
path_add LD_LIBRARY_PATH /opt/lib

# Remove from PATH
PATH_rm "*/.git/bin"
环境文件加载
# Load .env file (current directory)
dotenv

# Load specific file
dotenv .env.local

# Load only if exists (no error)
dotenv_if_exists .env.local
dotenv_if_exists .env.${USER}

# Source another .envrc
source_env ../.envrc
source_env /path/to/.envrc

# Search upward and source parent .envrc
source_up

# Source if exists
source_env_if_exists .envrc.local
语言布局

Node.js:

# Adds node_modules/.bin to PATH
layout node

Python:

# Creates virtualenv in .direnv/python-X.X/
layout python

# Use specific Python version
layout python python3.11

# Shortcut for Python 3
layout python3

# Use Pipenv (reads from Pipfile)
layout pipenv

Ruby:

# Sets GEM_HOME to project directory
layout ruby

Go:

# Modifies GOPATH and adds bin to PATH
layout go

Perl:

# Configures local::lib environment
layout perl
Nix 集成
# Load nix-shell environment
use nix

# With specific file
use nix shell.nix

# Load from Nix flake
use flake

# Load specific flake
use flake "nixpkgs#hello"
use flake ".#devShell"

如需更好地支持 Nix Flakes,请安装 nix-direnv:

# Provides faster, cached use_flake implementation
# https://github.com/nix-community/nix-direnv
版本管理器
# rbenv
use rbenv

# Node.js (with fuzzy version matching)
use node 18
use node 18.17.0

# Reads from .nvmrc if version not specified
use node

# Julia
use julia 1.9
验证
# Require environment variables (errors if missing)
env_vars_required API_KEY DATABASE_URL SECRET_KEY

# Enforce minimum direnv version
direnv_version 2.32.0

# Check git branch
if on_git_branch main; then
  export DEPLOY_ENV=production
fi
if on_git_branch develop; then
  export DEPLOY_ENV=staging
fi
文件监视
# Reload when files change
watch_file package.json
watch_file requirements.txt
watch_file .tool-versions
watch_file config/*.yaml

# Watch entire directory
watch_dir config
watch_dir migrations
实用函数
# Check if command exists
if has docker; then
  export DOCKER_HOST=unix:///var/run/docker.sock
fi

# Expand relative path to absolute
expand_path ./bin

# Find file searching upward
find_up package.json

# Enable strict mode (exit on errors)
strict_env

# Load prefix (configures CPATH, LD_LIBRARY_PATH, etc.)
load_prefix /usr/local/custom

# Load remote script with integrity verification
source_url https://example.com/script.sh "sha256-HASH..."

最佳实践

推荐的 .envrc 模板
#!/usr/bin/env bash
# .envrc - Project environment configuration

# Enforce direnv version for team consistency
direnv_version 2.32.0

# Load .env if exists
dotenv_if_exists

# Load local overrides (not committed to git)
source_env_if_exists .envrc.local

# Language-specific layout
layout node  # or: layout python3

# Add project bin directories
PATH_add bin
PATH_add scripts

# Development defaults
export NODE_ENV="${NODE_ENV:-development}"
export LOG_LEVEL="${LOG_LEVEL:-debug}"

# Watch for dependency changes
watch_file package.json
watch_file .nvmrc
Git 配置

.gitignore:

# Environment files with secrets
.env
.env.local
.envrc.local

# direnv virtualenv/cache
.direnv/

提交到仓库:

  • .envrc(基础配置,不包含密钥)
  • .env.example(供团队成员使用的模板)
密钥管理

**切勿提交密钥。**使用环境变量回退值:

# .envrc (committed)
export DATABASE_URL="${DATABASE_URL:-postgres://localhost/dev}"
export API_KEY="${API_KEY:-}"

# Validate required secrets
env_vars_required API_KEY

# .envrc.local (gitignored)
export DATABASE_URL="postgres://user:secret@prod/app"
export API_KEY="actual-secret-key"
分层配置
# ~/projects/.envrc (global dev settings)
export EDITOR=vim

# ~/projects/api/.envrc
source_up
export API_PORT=3000

# ~/projects/api/feature/.envrc
source_up
export FEATURE_FLAG=true
项目结构
my-project/
├── .envrc           # Base environment (committed)
├── .envrc.local     # Local overrides (gitignored)
├── .env             # Environment variables (gitignored)
├── .env.example     # Template for team (committed)
└── .direnv/         # direnv cache (gitignored)

自定义扩展

创建 ~/.config/direnv/direnvrc 来定义自定义函数:

#!/usr/bin/env bash
# ~/.config/direnv/direnvrc

# Custom function: Use specific Kubernetes context
use_kubernetes() {
  local context="${1:-default}"
  export KUBECONFIG="${HOME}/.kube/config"
  kubectl config use-context "$context" >/dev/null 2>&1
  log_status "kubernetes context: $context"
}

# Custom function: Load from AWS Secrets Manager
use_aws_secrets() {
  local secret_name="$1"
  local region="${2:-us-east-1}"
  eval "$(aws secretsmanager get-secret-value \
    --secret-id "$secret_name" \
    --region "$region" \
    --query SecretString \
    --output text | jq -r 'to_entries | .[] | "export \(.key)=\"\(.value)\""')"
  log_status "loaded secrets from: $secret_name"
}

# Custom function: Use asdf versions from .tool-versions
use_asdf() {
  watch_file .tool-versions
  source_env "$(asdf direnv local)"
}

在 .envrc 中使用:

use kubernetes dev-cluster
use aws_secrets myapp/dev
use asdf

命令参考

命令说明
direnv allow允许当前 .envrc
direnv deny撤销 .envrc 的访问权限
direnv reload强制重新加载环境
direnv status显示当前状态
direnv dump转储当前环境
direnv edit在编辑器中打开 .envrc
direnv version显示 direnv 版本

故障排除

环境未加载
# Check status
direnv status

# Force reload
direnv reload

# Re-allow .envrc
direnv allow

# Check if hook is installed
echo $DIRENV_DIR
Shell 钩子问题
  1. 确认钩子位于 shell 配置文件中
  2. 确保钩子位于文件末尾
  3. 完全重启 shell:exec $SHELL
  4. 检查错误:direnv hook zsh
性能问题
# Show what's being evaluated
direnv show_dump

# For Nix, use nix-direnv for caching
# https://github.com/nix-community/nix-direnv
调试
# Verbose output
export DIRENV_LOG_FORMAT='%s'

# Show exported variables
direnv dump | jq

# Test .envrc syntax
bash -n .envrc

IDE 集成

VS Code

安装 direnv 扩展,以便在集成终端中自动加载环境。

JetBrains

安装 direnv integration plugin。

Neovim

使用 direnv.vim,或使用 lua 进行配置。

常见模式

开发与生产环境
# .envrc
export NODE_ENV="${NODE_ENV:-development}"

if [[ "$NODE_ENV" == "development" ]]; then
  export DEBUG=true
  export LOG_LEVEL=debug
else
  export DEBUG=false
  export LOG_LEVEL=info
fi
多服务项目(Monorepo)
# root/.envrc
export PROJECT_ROOT="$(pwd)"
export COMPOSE_PROJECT_NAME=myapp

# services/api/.envrc
source_up
export SERVICE_NAME=api
export SERVICE_PORT=3000

# services/web/.envrc
source_up
export SERVICE_NAME=web
export SERVICE_PORT=8080
Docker 集成
# .envrc
export COMPOSE_FILE=docker-compose.yml
export COMPOSE_PROJECT_NAME="${PWD##*/}"

if has docker-compose; then
  export DOCKER_HOST="${DOCKER_HOST:-unix:///var/run/docker.sock}"
fi

# Add Docker bin for containers that install CLI tools
PATH_add .docker/bin

参考资料


注意事项

  • direnv 会在执行 cd 时重新加载,但编辑 .envrc 后不会,除非重新进入该目录: 更改 .envrc 后看起来已生效(没有报错),但要执行 cd . 或 direnv reload 才会生效。如果直接在文件中编辑,请对 .envrc 本身使用 watch_file。
  • direnv allow 根据文件内容哈希而非路径进行授权: 将 .envrc.dev 重命名为 .envrc 再改回来,授权状态仍会保留。但哪怕只改动一个字节也会撤销授权,包括在新编辑器中保存时意外添加的尾随换行符。
  • layout python 会创建与主机 Python 版本绑定的 .direnv/python-X.Y/: Python 升级会导致虚拟环境悄然失效。可通过 layout python python3.11 固定版本,或使用 rm -rf .direnv && direnv reload 重新构建。
  • source_up 会搜索所有祖先目录,而不仅是直接父目录: ~/ 或 ~/Projects/ 中意外存在的 .envrc 会影响其中的每个子目录项目。可在目录树深处执行 direnv status,查看所有串联的文件并进行检查。
  • 在 .zshrc 中,钩子的放置顺序很重要: 将 eval "$(direnv hook zsh)" 放在提示符/p10k 设置之后。若放置得更早,precmd 钩子会在提示符就绪前触发,direnv 的输出会被提示符重绘覆盖。
  • PATH_add bin 添加的项目相对路径可能会在脚本执行 cd 到其他位置时出问题: PATH 条目是绝对路径(加载时解析),因此执行 cd /tmp && project-binary 仍然有效,但运行时读取 $PWD/bin 的二进制文件则不行。

评论

支持 Markdown