nutools/lib/ulib/base.core

341 lines
11 KiB
Plaintext
Raw Normal View History

##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Fonctions de base: fondement
##@cooked nocomments
uprovide base.core
function echo_() {
# afficher la valeur $* sans passer à la ligne
echo -n "$*"
}
function recho() {
# afficher une valeur brute. contrairement à la commande echo, ne reconnaitre
# aucune option (i.e. -e, -E, -n ne sont pas signifiants)
if [[ "${1:0:2}" == -[eEn] ]]; then
echo -n -
local first="${1:1}"; shift
echo "$first$@"
else
echo "$@"
fi
}
function recho_() {
# afficher une valeur brute, sans passer à la ligne. contrairement à la commande
# echo, ne reconnaitre aucune option (i.e. -e, -E, -n ne sont pas signifiants)
if [[ "${1:0:2}" == -[eEn] ]]; then
echo -n -
local first="${1:1}"; shift
echo -n "$first$@"
else
echo -n "$@"
fi
}
function _rval() {
# Dans la chaine $*, remplacer \ par \\, " par \", $ par \$, ` par \`, SPACE par
# \SPACE
# Cela permet de quoter une chaine à afficher telle quelle, sans guillemets, e.g
# eval "echo $(_rval "$value")"
# Note: la protection de ! n'est pas effectuée, parce que le comportement du
# shell est incohérent entre le shell interactif et les scripts. Pour une
# version plus robuste, il est nécessaire d'utiliser un programme externe tel
# que sed ou awk
local s="$*"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//\$/\\\$}"
s="${s//\`/\\\`}"
s="${s// /\\ }"
recho_ "$s"
}
function _qval() {
# Dans la chaine $*, remplacer \ par \\, " par \", $ par \$, ` par \`
# Cela permet de quoter une chaine à mettre entre guillements.
# Note: la protection de ! n'est pas effectuée, parce que le comportement du
# shell est incohérent entre le shell interactif et les scripts. Pour une
# version plus robuste, il est nécessaire d'utiliser un programme externe tel
# que sed ou awk
local s="$*"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//\$/\\\$}"
s="${s//\`/\\\`}"
recho_ "$s"
}
function should_quote() {
# Tester si la chaine $* doit être mise entre quotes
2014-12-17 11:25:17 +04:00
local l="${#1}"
# pour optimiser, toujours mettre entre quotes une chaine vide ou de plus de 80 caractères
[ $l -eq 0 -o $l -gt 80 ] && return 0
# sinon, tester si la chaine contient des caractères spéciaux
local s="${*//[a-zA-Z0-9]/}"
s="${s//,/}"
s="${s//./}"
s="${s//+/}"
s="${s//\//}"
s="${s//-/}"
s="${s//_/}"
s="${s//=/}"
[ -n "$s" ]
}
function qval() {
# Afficher la chaine $* quotée avec "
echo -n \"
_qval "$@"
echo \"
}
function qvalm() {
# Afficher la chaine $* quotée si nécessaire avec "
if should_quote "$*"; then
echo -n \"
_qval "$@"
echo \"
else
recho "$*"
fi
}
function qvalr() {
2014-09-19 15:31:33 +04:00
# Afficher la chaine $* quotée si nécessaire avec ", sauf si elle est vide
if [ -z "$*" ]; then
:
elif should_quote "$*"; then
echo -n \"
_qval "$@"
echo \"
2014-09-19 15:31:33 +04:00
else
recho "$*"
fi
}
function qvals() {
# Afficher chaque argument de cette fonction quotée le cas échéant avec "
# Chaque valeur est séparée par un espace.
local arg first=1
for arg in "$@"; do
[ -z "$first" ] && echo -n " "
if should_quote "$arg"; then
echo -n \"
_qval "$arg"
echo -n \"
else
recho_ "$arg"
fi
first=
done
[ -z "$first" ] && echo
}
function qlines() {
# Traiter chaque ligne de l'entrée standard pour en faire des chaines quotées
# avec '
sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function setv() {
# initialiser la variable $1 avec la valeur $2*
# note: en principe, la syntaxe est 'setv var values...'. cependant, la
# syntaxe 'setv var=values...' est supportée aussi
local __s_var="$1"; shift
if [[ "$__s_var" == *=* ]]; then
set -- "${__s_var#*=}" "$@"
__s_var="${__s_var%%=*}"
fi
2014-12-17 11:25:17 +04:00
eval "$__s_var=\"\$*\""
}
function _setv() {
# Comme la fonction setv() mais ne supporte que la syntaxe '_setv var values...'
# Cette fonction est légèrement plus rapide que setv()
local __s_var="$1"; shift
2014-12-17 11:25:17 +04:00
eval "$__s_var=\"\$*\""
}
2014-09-19 15:22:55 +04:00
function echo_setv() {
# Afficher la commande qui serait lancée par setv "$@"
local __s_var="$1"; shift
if [[ "$__s_var" == *=* ]]; then
set -- "${__s_var#*=}" "$@"
__s_var="${__s_var%%=*}"
fi
2014-09-19 15:31:33 +04:00
echo "$__s_var=$(qvalr "$*")"
2014-09-19 15:22:55 +04:00
}
function setx() {
# syntaxe 1: setx var cmd
# initialiser la variable $1 avec le résultat de la commande "$2..@"
# note: en principe, la syntaxe est 'setx var cmd args...'. cependant, la
# syntaxe 'setx var=cmd args...' est supportée aussi
# syntaxe 2: setx -a array cmd
# initialiser le tableau $1 avec le résultat de la commande "$2..@", chaque
# ligne du résultat étant un élément du tableau
# note: en principe, la syntaxe est 'setx -a array cmd args...'. cependant, la
# syntaxe 'setx -a array=cmd args...' est supportée aussi
if [ "$1" == -a ]; then
shift
local __s_array="$1"; shift
if [[ "$__s_array" == *=* ]]; then
set -- "${__s_array#*=}" "$@"
__s_array="${__s_array%%=*}"
fi
eval "$__s_array=($("$@" | qlines))"
else
local __s_var="$1"; shift
if [[ "$__s_var" == *=* ]]; then
set -- "${__s_var#*=}" "$@"
__s_var="${__s_var%%=*}"
fi
eval "$__s_var="'"$("$@")"'
fi
}
function _setvx() {
# Comme la fonction setx() mais ne supporte que l'initialisation d'une variable
# scalaire avec la syntaxe '_setvx var cmd args...' pour gagner (un peu) en
# rapidité d'exécution.
local __s_var="$1"; shift
eval "$__s_var="'"$("$@")"'
}
function _setax() {
# Comme la fonction setx() mais ne supporte que l'initialisation d'un tableau
# avec la syntaxe '_setax array cmd args...' pour gagner (un peu) en rapidité
# d'exécution.
local __s_array="$1"; shift
eval "$__s_array=($("$@" | qlines))"
}
function evalx() {
# Implémenter une syntaxe lisible et naturelle permettant d'enchainer des
# traitements sur une valeur. Par exemple, la commande
# evalx cmd1... // cmd2... // cmd3...
# affiche le résultat de la commande "$(cmd3 $(cmd2 $(cmd1)))"
# Retourner le dernier code d'erreur non nul, ou 0 si toutes les commandes se
# sont exécutées sans erreur.
local __e_val __e_arg __e_r=0
local -a __e_cmd
local __e_first=1
while [ $# -gt 0 ]; do
__e_cmd=()
while [ $# -gt 0 ]; do
__e_arg="$1"; shift
[ "$__e_arg" == // ] && break
if [ "${__e_arg%//}" != "$__e_arg" ]; then
local __e_tmp="${__e_arg%//}"
if [ -z "${__e_tmp//\\/}" ]; then
__e_arg="${__e_arg#\\}"
__e_cmd=("${__e_cmd[@]}" "$__e_arg")
continue
fi
fi
__e_cmd=("${__e_cmd[@]}" "$__e_arg")
done
if [ -n "$__e_first" ]; then
__e_val="$("${__e_cmd[@]}")" || __e_r=$?
else
__e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
fi
__e_first=
done
[ -n "$__e_val" ] && echo "$__e_val"
return $__e_r
}
function setxx() {
# équivalent à setx $1 evalx $2..@
local -a __s_args
if [ "$1" == -a ]; then __s_args=(-a); shift; fi
local __s_var="$1"; shift
if [[ "$__s_var" == *=* ]]; then
set -- "${__s_var#*=}" "$@"
__s_var="${__s_var%%=*}"
fi
__s_args=("${__s_args[@]}" "$__s_var")
setx "${__s_args[@]}" evalx "$@"
}
function evalp() {
# Implémenter une syntaxe alternative permettant d'enchainer des traitements sur
# un flux de données. Par exemple, la commande
# evalp cmd1... // cmd2... // cmd3...
# affiche le résultat de la commande "$(cmd1 | cmd2 | cmd3)"
# Typiquement, cette fonction permet de faciliter la construction d'un
# enchainement de commandes par programme, ou de faciliter l'utilisation de la
# fonction setx() pour récupérer le résultat d'un enchainement. Dans les autres
# cas, il est plus simple et naturel d'écrire les enchainements avec la syntaxe
# de bash.
local __e_arg __e_cmd
while [ $# -gt 0 ]; do
__e_arg="$1"; shift
if [ "$__e_arg" == // ]; then
__e_cmd="$__e_cmd |"
continue
elif [ "${__e_arg%//}" != "$__e_arg" ]; then
local __e_tmp="${__e_arg%//}"
if [ -z "${__e_tmp//\\/}" ]; then
__e_arg="${__e_arg#\\}"
fi
fi
__e_cmd="${__e_cmd:+$__e_cmd }\"$(_qval "$__e_arg")\""
done
eval "$__e_cmd"
}
function setxp() {
# équivalent à setx $1 evalp $2..@
local -a __s_args
if [ "$1" == -a ]; then __s_args=(-a); shift; fi
local __s_var="$1"; shift
if [[ "$__s_var" == *=* ]]; then
set -- "${__s_var#*=}" "$@"
__s_var="${__s_var%%=*}"
fi
__s_args=("${__s_args[@]}" "$__s_var")
setx "${__s_args[@]}" evalp "$@"
}
function testx() {
# Faire un test unaire avec la commande [ sur une valeur calculée avec evalx.
# Utiliser la syntaxe 'testx op cmds...' e.g.
# testx -z cmd1 // cmd2
local __t_op="$1"; shift
local __t_val="$(evalx "$@")"
[ $__t_op "$__t_val" ]
}
function test2x() {
# Faire une test binaire avec la commande [ entre une valeur spécifiée et une
# valeur calculée avec evalx. Utiliser la syntaxe 'test2x value op cmds...' e.g.
# test2x value == cmd1 // cmd2
local __t_val1="$1"; shift
local __t_op="$1"; shift
local __t_val2="$(evalx "$@")"
[ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrx() {
# Faire une test binaire avec la commande [[ entre une valeur spécifiée et une
# valeur calculée avec evalx. Utiliser la syntaxe 'testrx value op cmds...' e.g.
# testrx value == cmd1 // cmd2
local __t_val1="$1"; shift
local __t_op="$1"; shift
local __t_val2="$(evalx "$@")"
eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function testp() {
# Faire un test unaire avec la commande [ sur une valeur calculée avec evalp.
# Utiliser la syntaxe 'testp op cmds...' e.g.
# testp -z cmd1 // cmd2
local __t_op="$1"; shift
local __t_val="$(evalp "$@")"
[ $__t_op "$__t_val" ]
}
function test2p() {
# Faire une test binaire avec la commande [ entre une valeur spécifiée et une
# valeur calculée avec evalp. Utiliser la syntaxe 'test2p value op cmds...' e.g.
# test2p value == cmd1 // cmd2
local __t_val1="$1"; shift
local __t_op="$1"; shift
local __t_val2="$(evalp "$@")"
[ "$__t_val1" $__t_op "$__t_val2" ]
}
function testrp() {
# Faire une test binaire avec la commande [[ entre une valeur spécifiée et une
# valeur calculée avec evalp. Utiliser la syntaxe 'testrp value op cmds...' e.g.
# testrp value == cmd1 // cmd2
local __t_val1="$1"; shift
local __t_op="$1"; shift
local __t_val2="$(evalp "$@")"
eval '[[ "$__t_val1" '"$__t_op"' "$__t_val2" ]]'
}
function err2out() {
# lancer la commande $@ en redirigeant la sortie d'erreur sur la sortie standard
"$@" 2>&1
}