#1 Le 26/12/2024, à 01:50
- Totor
[Script/bash] Sortie standard & d'erreur dans des variables distinctes
Hello,
Suite à la demande d'un collègue, je partage ici une fonction permettant de récupérer la sortie standard et la sortie d'erreur d'une commande dans des variables distinctes.
#!/bin/bash
function fReadStdAndErr() {
declare -r nullChar=$'\0'
function myRead() {
local _myLine=""
local _fd=$1
local _endChar="$2"
while read -u ${_fd}
do
[[ ${REPLY} == ${_endChar} ]] && break
_myLine="$(printf "${_myLine}\n${REPLY}")"
done
echo "${_myLine/$'\n'}"
}
# Instruction à exécuter (avec paramètres)
local _cmd="$1"
# Nom de la variable dans laquelle mettre le contenu de la sortie standard
local _varStd="$2"
# Nom de la variable dans laquelle mettre le contenu de la sortie d'erreur
local _varErr="$3"
coproc MY_COPROC_READ {
# exécution de la commande avec récupération de la sortie d'erreur+\0+status dans la variable "err"
# une fois la commande exécutée, on envoie le caractère de \0 afin de signaler à la méthode "myRead" que c'est tout bon pour la sortie standard
{ local err="$( eval ${_cmd} 2>&1 >&3; local _status=$?; echo ${nullChar}; echo ${_status})"; echo "${nullChar}"; } 3>&1
# On attend que quelque chose arrive en entrée standard pour envoyer le contenu de la variable "err" + nullChar
read
echo "${err}"
echo "${nullChar}"
# On attend que quelque chose arrive en entrée standard (donc fin de récupération de la variable "err + status") pour terminer le coproc
read
}
# On récupère le contenu de la sortie standard du coproc (ie. sortie standard de la commande)
local _std="$(myRead ${MY_COPROC_READ[0]} "${nullChar}")"
# on indique au coproc que l'on a fini de lire la sortie standard et qu'il peut envoyer le contenu de la variable err qui contient la sortie d'erreur + nullChar + status
echo >&${MY_COPROC_READ[1]}
# Récupération de la sortie d'erreur
local _err="$(myRead ${MY_COPROC_READ[0]} "${nullChar}")"
# récupération du status de fin
local _st="$(myRead ${MY_COPROC_READ[0]} "${nullChar}")"
# On indique au coproc que l'on a tout récupéré
echo >&${MY_COPROC_READ[1]}
# on valorise les 2 variables fournies en paramètres
eval "${_varStd}=$'$(cat <<QUOTE
${_std//"'"/"\'"}
QUOTE
)'"
eval "${_varErr}=$'$(cat <<QUOTE
${_err//"'"/"\'"}
QUOTE
)'"
return ${_st}
}
fReadStdAndErr "Commande à exécuter (avec ses arguments)" nomVariableDestinationSortieStandard nomVariableDestinationSortieErreur
Note : la foncton fReadStdAndErr retourne le status de la commande à exécuter
Même si je ne suis pas fan, "eval" a été utilisé pour :
- exécuter la commande (il est possible de s'en passer mais cela est limitant --> la 2nde forme de l'exemple ci-dessous ne serait pas possible)
- définir la valeur des variables contenant les sorties standard et d'erreur
Exemples d'utilisation :
cmd='ls -ld b* _W* D*'
fReadStdAndErr "${cmd}" standard erreur
status=$?
echo "cmd : ${cmd}"
echo "Standard : ${standard}"
echo "Erreur : ${erreur}"
echo "Status : ${status}"
echo
echo "-------------------------------"
cmd="{ echo erreur >&2 ; echo standard; }"
fReadStdAndErr "${cmd}" standard erreur
status=$?
echo "cmd : ${cmd}"
echo "Standard : ${standard}"
echo "Erreur : ${erreur}"
echo "Status : ${status}"
-- Lucid Lynx --
Hors ligne
#2 Le 26/12/2024, à 03:42
- Watael
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
d'un point de vue formel :
function et () sont redondants (c'est l'un ou l'autre)
il n'y a pas de gain à déclarer une fonction dans une autre fonction
une substitution de commandes ($(...)) s'exécutant dans un sous-shell, les variables qui y sont assignées lui sont forcément "locales"
tu pourrais déclarer toutes les variables au début de la fonction, avant leur utilisation; si toutes les variables de la fonction sont locales, alors la fonction peut être exécutée dans une sous-shell (foncLocaleVar() ( ...))
le script n'appelle pas la fonction, alors comment est-elle exécutée ?
ton exemple ne montre pas le fonctionnement du script :
comment on lui passe la commande
la disponibilité des variables dont le nom est passé en arguments
je me serais contenté, pour faire simple (KISS), de rediriger stdout et stderr vers des fichiers et de lire ces fichiers dans des variables...
c'est lisible, et il n'y a pas de temps de traitements supplémentaire
Dernière modification par Watael (Le 26/12/2024, à 03:45)
Connected \o/
Welcome to sHell. · eval is evil.
Hors ligne
#3 Le 26/12/2024, à 06:58
- Tawal
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
Hello.
Ou si on ne veut pas d'écriture sur le disque, on peut utiliser des fifos (un par sortie).
Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !
Hors ligne
#4 Le 27/12/2024, à 11:09
- Totor
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
d'un point de vue formel :
function et () sont redondants (c'est l'un ou l'autre)
il n'y a pas de gain à déclarer une fonction dans une autre fonction
une substitution de commandes ($(...)) s'exécutant dans un sous-shell, les variables qui y sont assignées lui sont forcément "locales"
tu pourrais déclarer toutes les variables au début de la fonction, avant leur utilisation; si toutes les variables de la fonction sont locales, alors la fonction peut être exécutée dans une sous-shell (foncLocaleVar() ( ...))le script n'appelle pas la fonction, alors comment est-elle exécutée ?
ton exemple ne montre pas le fonctionnement du script :
comment on lui passe la commande
la disponibilité des variables dont le nom est passé en argumentsje me serais contenté, pour faire simple (KISS), de rediriger stdout et stderr vers des fichiers et de lire ces fichiers dans des variables...
c'est lisible, et il n'y a pas de temps de traitements supplémentaire
C'est bien, je suis content, ça me fait de belles jambes...
Hello.
Ou si on ne veut pas d'écriture sur le disque, on peut utiliser des fifos (un par sortie).
Hello,
Oui, tout à fait. c'est également une piste que j'avais envisagé mais elle implique la même problématique que les fichiers (que je n'aime pas): il faut gérer la création / suppression afin de laisser le système dans le même état qu'avant l'exécution de la fonction (je pense particulièrement à un arrêt non maitrisé du script durant l'exécution de la commande). Alors que là, c'est le coproc qui s'en charge.
Mais quoi qu'il en soit, l'utilisation de fifo te fera retomber dans une gestion asynchrone de lecture des flux. Il te faudra également récupérer le statut de la commande.
Au final, je pense que ce cela reviendra au même. Cela reste une question d'appréciation / préférence de codage.
Merci de l'avoir souligné.
-- Lucid Lynx --
Hors ligne
#5 Le 27/12/2024, à 16:08
- Tawal
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
Une solution en utilisant les fifos (pas de gestion de création/suppression : aussitôt créé, aussitôt supprimé)
get_sdt_err_status()
{
local -n std="$2" err="$3" stat="$4"
standard="$(mktemp -up /tmp sdtXXXXXXXX)"
mkfifo $standard
exec 8<>$standard 4<$standard 5>$standard 8>&-
rm $standard
erreur="$(mktemp -up /tmp errXXXXXXXX)"
mkfifo $erreur
exec 8<>$erreur 6<$erreur 7>$erreur 8>&-
rm $erreur
1>&5 2>&7 eval "$1"
stat=$?
>&5 echo "EOF"
>&7 echo "EOF"
while read -r e <&6
do
[ "$e" = "EOF" ] && break
printf -v tmp "%s\n" "$e"
err+="$tmp"
done
while read -r s <&4
do
[ "$s" = "EOF" ] && break
printf -v tmp "%s\n" "$s"
std+="$tmp"
done
exec 4>&- 5>&- 6>&- 7>&-
}
# Exemple d'utilisation :
cmd="ls -l t* zzz yyy"
get_sdt_err_status "$cmd" norm rate code
echo "N= $norm"
echo "E= $rate"
echo "C= $code"
Dernière modification par Tawal (Le 27/12/2024, à 17:04)
Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !
Hors ligne
#6 Le 27/12/2024, à 16:44
- Watael
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
tu ne voulais pas faire mkfifo $standard ?
sinon, à quoi sert le mktemp ?
Connected \o/
Welcome to sHell. · eval is evil.
Hors ligne
#7 Le 27/12/2024, à 17:03
- Tawal
Re : [Script/bash] Sortie standard & d'erreur dans des variables distinctes
Euh si !
Je corrige
Edit:
@Totor: Tu devrais utiliser les "belles jambes" que t'a fourni Watael
Dernière modification par Tawal (Le 27/12/2024, à 17:20)
Le savoir n'a d’intérêt que si on le transmet.
Useless Use of Cat Award
Filenames and Pathnames in Shell: How to do it Correctly
À chaque problème sa solution, à chaque solution son moyen, si pas de moyen, toujours le problème !
Hors ligne