objectif
Charger des variables depuis un fichier .env sans exécuter de code, en acceptant KEY=VALUE (quotes optionnelles), en gérant CRLF et une liste de clés autorisées.
code minimal
# charge .env de manière sûre (KEY=VALUE), sans eval/source
# usage: safe_env_load .env "APP_PORT APP_NAME DB_URL"
safe_env_load() {
local file="${1:-.env}"; shift || true
local whitelist=" $* "
[ -r "$file" ] || { echo "absent: $file" >&2; return 0; }
local line key val
while IFS= read -r line || [ -n "$line" ]; do
# ignorer vides/commentaires
[[ "$line" =~ ^[[:space:]]*$ ]] && continue
[[ "$line" =~ ^[[:space:]]*\# ]] && continue
# parse: KEY = VALUE (quotes optionnelles)
if [[ "$line" =~ ^[[:space:]]*([A-Za-z_][A-Za-z0-9_]*)[[:space:]]*=[[:space:]]*(.*)[[:space:]]*$ ]]; then
key="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[2]}"
# enlever CR final (fichiers CRLF)
val="${val%$'\r'}"
# retirer quotes englobantes si presentes
if [[ "$val" =~ ^\"(.*)\"$ ]]; then val="${BASH_REMATCH[1]}"; fi
if [[ "$val" =~ ^\'(.*)\'$ ]]; then val="${BASH_REMATCH[1]}"; fi
# refuser expansions/substitutions dangereuses
if [[ "$val" =~ [\`\$]|\$\(|\)\>|\<\(|\|\| ]]; then
echo "ligne suspecte ignoree pour $key" >&2
continue
fi
# si whitelist fournie, ne charger que ces cles
if [ -n "${whitelist// }" ] && [[ " $whitelist " != *" $key "* ]]; then
continue
fi
# assigner sans eval, exporter
printf -v "$key" '%s' "$val"
export "$key"
fi
done < "$file"
}
utilisation
# exemple de .env
cat > .env <<'EOF'
# commentaire
APP_NAME="demo app"
APP_PORT=8080
DB_URL=postgres://user:pass@localhost:5432/app
EOF
# charger uniquement les cles necessaires
safe_env_load .env "APP_NAME APP_PORT DB_URL"
# verifier
printf 'APP_NAME=%q\nAPP_PORT=%q\nDB_URL=%q\n' "$APP_NAME" "$APP_PORT" "$DB_URL"
# utiliser ensuite avec envsubst, app, etc.
envsubst '${APP_NAME} ${APP_PORT}' < config.tmpl > config.conf
variante(s) utile(s)
# charger toutes les cles sans whitelist (attention a ce que contient .env)
safe_env_load .env
# charger puis lancer une commande avec env propre (sans variables parasites)
( env -i PATH="$PATH" HOME="$HOME" bash -lc 'safe_env_load .env "APP_NAME APP_PORT"; ./start.sh' )
# ecrire un .env nettoye (quotes evaporees, CRLF supprime, uniquement whitelist)
safe_env_load .env "APP_NAME APP_PORT DB_URL"
{
printf 'APP_NAME=%s\n' "$APP_NAME"
printf 'APP_PORT=%s\n' "$APP_PORT"
printf 'DB_URL=%s\n' "$DB_URL"
} > .env.cleaned
# fallback simple (moins strict) si Bash n'est pas disponible: set -a/. (risques)
# set -a; . ./.env; set +a
notes
- ne faites pas
source .env: cela execute du code arbitraire. Le parsing ci-dessus n’evalue rien. - seuls les formats
KEY=VALUE(quotes optionnelles) sont pris en charge; pas d’export, pas de substitutions shell. - utilisez la whitelist pour limiter ce qui entre dans votre environnement (principe du moindre privilege).
- pour des besoins complexes (multilignes, escapes), utilisez un parseur dedie (ex: Python
dotenv), ou formalisez en JSON/YAML.