objectif
Déboguer un script bash sans polluer stderr: activer set -x avec un préfixe riche (timestamp ISO, fichier, ligne, fonction) et écrire le trace dans un fichier via BASH_XTRACEFD.
code minimal
# activer xtrace horodaté vers un fichier (sans polluer stderr)
log="./xtrace.$(date -u +%Y-%m-%d).log"
exec 3>>"$log"
export BASH_XTRACEFD=3
export PS4='+ $(date -u +%Y-%m-%dT%H:%M:%SZ) ${BASH_SOURCE##*/}:${LINENO}:${FUNCNAME[0]:-main}: '
set -x
utilisation
#!/usr/bin/env bash
set -Eeuo pipefail
# xtrace dédié (logs dans ./logs/ avec rotation simple)
mkdir -p ./logs
exec 3>>"./logs/xtrace-$(date -u +%Y-%m-%d).log"
export BASH_XTRACEFD=3
export PS4='+ $(date -u +%Y-%m-%dT%H:%M:%SZ) ${BASH_SOURCE##*/}:${LINENO}:${FUNCNAME[0]:-main}: '
set -x
deploy_www() {
local dest="/srv/data.pm/current"
rsync -a --delete ./build/ "$dest/"
touch "$dest/.deployed"
}
# masquer une section sensible (tokens, mots de passe)
set +x
API_TOKEN="$(< ./secrets/api.token)"
set -x
curl -fsS -H "Authorization: Bearer $API_TOKEN" https://api.data.pm/health -o /dev/null
deploy_www
variante(s) utile(s)
# fonction toggle: enable/disable xtrace avec fichier passé en argument
xtrace_on() {
local log="${1:-./xtrace.log}"
exec 3>>"$log"
export BASH_XTRACEFD=3
export PS4='+ $(date -u +%Y-%m-%dT%H:%M:%SZ) ${BASH_SOURCE##*/}:${LINENO}:${FUNCNAME[0]:-main}: '
set -x
}
xtrace_off() {
set +x
exec 3>&- || true
}
# envoyer aussi au syslog (copie asynchrone) sans casser le retour de code
tail -F "./logs/xtrace-$(date -u +%Y-%m-%d).log" | logger -t data.pm -p user.debug &
# capturer xtrace uniquement pour une commande (subshell)
( exec 3>>./logs/one-shot.log; BASH_XTRACEFD=3 PS4='+ $(date -u +%H:%M:%S) ${BASH_SOURCE##*/}:${LINENO}: ' bash -x -c 'make -s build' )
# réduire le coût CPU du timestamp: préfixe figé par run (moins précis mais rapide)
export PS4='+ '"$(date -u +%Y-%m-%dT%H:%M:%SZ)"' ${BASH_SOURCE##*/}:${LINENO}:${FUNCNAME[0]:-main}: '
set -x
# isoler le trace d'un module sourcé
module_log="./logs/module-$(date -u +%Y-%m-%d).log"
( exec 3>>"$module_log"; BASH_XTRACEFD=3 PS4='+ $(date -u +%H:%M:%S) ${BASH_SOURCE##*/}:${LINENO}: ' bash -x module.sh )
notes
BASH_XTRACEFDredirige leset -xvers un descripteur indépendant (ici 3), évitant de mélanger trace et sorties de la commande.PS4définit le préfixe par ligne de trace. Les expansions utiles:${BASH_SOURCE##*/},${LINENO},${FUNCNAME[0]}.set +xautour des secrets empêche de les divulguer dans les logs. Vérifiez aussi vos variables d’environnement.- ouvrez le FD avec
>>(append) et des permissions strictes sur le dossier de logs (0700/fichiers0600) si sensibles. - la commande
dates’exécute à chaque ligne tracée (coût modéré). Pour diminuer l’overhead, figez une partie du préfixe (variante ci-dessus).