读取config_files下.env文件并导出为环境变量的问题排查
读取.env文件设置环境变量失败的解决方案
问题背景
尝试读取config_files目录下所有.env文件,将其中内容设为环境变量,但多种脚本尝试后均失败,具体情况如下:
已尝试的脚本及异常情况
- 脚本1:
#! /bin/bash for file in "$(find ~/config_files -maxdepth 3 -name '*.env')"; do export $(grep -v '^#' $file | xargs); done
- 脚本2:
#! /bin/bash for file in "$(find ~/config_files -regex '.*/.*\.\(env\)$')"; do export $(xargs < $file); done
上述两个脚本运行后出现类似declare -x COLORTERM="truecolor"的异常输出。
- 脚本3(添加
-print参数):
for file in "$(find ~/.ros/PS_AD/config_files -maxdepth 3 -name '*.env' -print)"; do export $(grep -v '^#' $file | xargs); done
运行后报错:
./script: line 3: export: `/home/imr/config_files/docker-image/docker_specs.env:random=1': not a valid identifier
.env文件内容示例:
random=1
- 后续尝试(仍失败)
改用IFS+read的标准写法:
find ~/config_files -name '*.env' -print0 | while IFS= read -r -d '' line; do echo $line set -a . "$line" set +a done
环境变量未生效。
再尝试管道 workaround:
while IFS= read -r -d '' p do set -a; . "$p"; set +a done < <(find ~/config_files -name '*.env' -type f -print0)
问题依旧。
问题根源
- 初始
for循环写法错误:"$(find ...)"会将所有找到的文件名拼接成单个字符串,导致循环仅执行一次,把文件名列表当成单个文件处理,进而grep+xargs会混淆文件名与文件内容,生成文件名=值的无效环境变量名。 - 管道子shell限制:通过
|管道调用的while循环会在子shell中执行,子shell内设置的环境变量无法传递到父shell,这是set -a写法仍不生效的核心原因。
正确实现方式
方式1:用Glob遍历(适合无特殊字符的文件名)
#! /bin/bash # 开启层级目录匹配与隐藏目录匹配 shopt -s globstar dotglob for file in ~/config_files/**/*.env; do # 确保仅处理文件(排除目录) [ -f "$file" ] || continue # 自动导出后续所有变量 set -a # 读取.env文件内容 . "$file" # 关闭自动导出 set +a done
globstar允许**匹配任意层级的子目录dotglob允许匹配隐藏目录下的.env文件
方式2:用mapfile+find(支持含特殊字符的文件名)
#! /bin/bash # 读取find输出的文件名数组(支持空格、换行等特殊字符) mapfile -d '' files < <(find ~/config_files -maxdepth 3 -name '*.env' -type f -print0) for file in "${files[@]}"; do set -a . "$file" set +a done
find -print0与mapfile -d ''配合,可安全处理包含特殊字符的文件名- 循环在当前shell执行,环境变量会直接生效
方式3:直接用find -exec(简洁写法)
#! /bin/bash find ~/config_files -maxdepth 3 -name '*.env' -type f -exec bash -c ' set -a . "$0" set +a ' {} \;
- 为每个
.env文件启动一个bash进程执行导入,变量会被导出到当前shell
内容的提问来源于stack exchange,提问作者ignacio
相关产品推荐
相关产品推荐

