314 lines
10 KiB
Bash
314 lines
10 KiB
Bash
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
## Fonctions de base: gestion des valeurs chaines scalaires
|
|
##@cooked nocomments
|
|
# Note: contient du code spécifique à bash 4. Le module base.compat réimplémente
|
|
# les fonctions concernées pour les rendre compatible avec bash >= 2.x
|
|
uprovide base.string
|
|
urequire base.core
|
|
|
|
# IMPORTANT: aucune des fonctions suivantes ne met en échappement les valeur des
|
|
# patterns. Ainsi, si un pattern contient des caractères interdits comme \ ou $,
|
|
# il faut d'abord le traiter avec _qval()
|
|
|
|
function straddp() {
|
|
# ajouter le préfixe $1 à $2..*
|
|
local p="$1"; shift
|
|
echo "$p$*"
|
|
}
|
|
function strdelp() {
|
|
# enlever le préfixe $1 à $2..*
|
|
local p="$1"; shift
|
|
local str="$*"
|
|
echo "${str#$p}"
|
|
}
|
|
function strdelp2() {
|
|
# enlever le préfixe $1 le plus long à $2..*
|
|
local p="$1"; shift
|
|
local str="$*"
|
|
echo "${str##$p}"
|
|
}
|
|
function stradds() {
|
|
# ajouter le suffixe $1 à $2..*
|
|
local s="$1"; shift
|
|
echo "$*$s"
|
|
}
|
|
function strdels() {
|
|
# enlever le suffixe $1 à $2..*
|
|
local s="$1"; shift
|
|
local str="$*"
|
|
echo "${str%$s}"
|
|
}
|
|
function strdels2() {
|
|
# enlever le suffixe le plus long $1 à $2..*
|
|
local s="$1"; shift
|
|
local str="$*"
|
|
echo "${str%%$s}"
|
|
}
|
|
function strlower() {
|
|
# afficher en minuscule la valeur $*
|
|
local str="$*"
|
|
echo "${str,,}"
|
|
}
|
|
function strlower1() {
|
|
# afficher la valeur $* après avoir converti la première lettre en minuscule
|
|
local str="$*"
|
|
echo "${str,}"
|
|
}
|
|
function strlowers() {
|
|
# afficher les valeurs $1..* après avoir converti leur première lettre en
|
|
# minuscule
|
|
local str="$*"
|
|
echo "${*,}"
|
|
}
|
|
function strupper() {
|
|
# afficher en majuscule la valeur $*
|
|
local str="$*"
|
|
echo "${str^^}"
|
|
}
|
|
function strupper1() {
|
|
# afficher la valeur $* après avoir converti la première lettre en majuscule
|
|
local str="$*"
|
|
echo "${str^}"
|
|
}
|
|
function struppers() {
|
|
# afficher les valeurs $1..* après avoir converti leur première lettre en
|
|
# majuscule
|
|
echo "${*^}"
|
|
}
|
|
function strmid() {
|
|
# Afficher la plage $1 de la valeur $2..*. La plage peut être d'une des formes
|
|
# 'start', '[start]:length'. Si start est négatif, le compte est effectué à
|
|
# partir de la fin de la chaine. Si length est négatif, il est rajouté à la
|
|
# longueur de la chaine à partir de start
|
|
local range="$1"; shift
|
|
local str="$*"
|
|
if [[ "$range" == *:-* ]]; then
|
|
local max=${#str}
|
|
[ $max -eq 0 ] && return
|
|
local start="${range%%:*}"
|
|
[ -n "$start" ] || start=0
|
|
while [ "$start" -lt 0 ]; do
|
|
start=$(($max$start))
|
|
done
|
|
max=$(($max-$start))
|
|
local length="${range#*:}"
|
|
while [ "$length" -lt 0 ]; do
|
|
length=$(($max$length))
|
|
done
|
|
range="$start:$length"
|
|
fi
|
|
eval 'echo "${str:'" $range"'}"'
|
|
}
|
|
function strrepl() {
|
|
# Remplacer dans la valeur $3..* le motif $1 par la chaine $2. $1 peut commencer
|
|
# par l'un des caractères /, #, % pour indiquer le type de recherche
|
|
local pattern="$1"; shift
|
|
local repl="$1"; shift
|
|
local str="$*"
|
|
local cmd='echo "${str/'
|
|
if [ "${pattern#/}" != "$pattern" ]; then
|
|
pattern="${pattern#/}"
|
|
cmd="$cmd/"
|
|
elif [ "${pattern#\#}" != "$pattern" ]; then
|
|
pattern="${pattern#\#}"
|
|
cmd="$cmd#"
|
|
elif [ "${pattern#%}" != "$pattern" ]; then
|
|
pattern="${pattern#%}"
|
|
cmd="$cmd%"
|
|
fi
|
|
cmd="$cmd"'$pattern/$repl}"'
|
|
eval "$cmd"
|
|
}
|
|
|
|
function strops() {
|
|
# Appliquer à une chaine de caractères une suite de traitements, e.g:
|
|
# 'strops var deref +suffix' est équivalent à 'echo "${var}suffix"'
|
|
# En commençant avec la valeur initiale $1, les arguments $2..* sont des
|
|
# opérations à appliquer dans l'ordre.
|
|
# Les opérations suivantes considèrent que la valeur courante est un nom de
|
|
# variable:
|
|
# :- := :? :+ deref dcount
|
|
# Toutes les autres opérations travaillent directement avec la valeur
|
|
# courante. Les opérations suivantes appliquent une transformation:
|
|
# # % / : ^ , +# -# +% -% + - mid repl
|
|
# Les opérations suivantes font un test sur la valeur et retournent
|
|
# immédiatement:
|
|
# = == != < > -eq -ne -lt -le -gt -ge -n -z
|
|
# La syntaxe des opérateurs standards de bash est reprise autant que possible,
|
|
# i.e si on a l'habitude d'écrire ${varOP} en bash, alors la syntaxe à utiliser
|
|
# à priori est 'strops var OP' ou 'strop var deref OP' suivant les opérateurs.
|
|
# Autres opérateurs:
|
|
# deref indirection
|
|
# dcount nombre d'éléments du tableau
|
|
# +#STR ajouter un préfixe
|
|
# -#STR supprimer un préfixe
|
|
# +%STR ou +STR ajouter un suffixe
|
|
# -%STR ou -STR supprimer un suffixe
|
|
# mid RANGE traiter la chaine avec strmid()
|
|
# repl FROM TO traiter la chaine avec strrepl()
|
|
local -a __s_tmp
|
|
local __s_value="$1"; shift
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
# l'argument est le nom de la variable
|
|
:-*|:=*|:\?*|:+*) eval '__s_value="${'"${__s_value}$1"'}"';;
|
|
d|deref) __s_value="${!__s_value}";;
|
|
dc|dcount|ds|dsize)
|
|
__s_value="${__s_value}[@]"
|
|
__s_tmp=("${!__s_value}")
|
|
__s_value="${#__s_tmp[@]}"
|
|
;;
|
|
# l'argument est la valeur de la variable
|
|
\#*|%*|/*|:*|^*|,*) eval '__s_value="${__s_value'"$1"'}"';;
|
|
l|length) __s_value="${#__s_value}";;
|
|
=|==|!=|\<|\>|-eq|-ne|-lt|-le|-gt|-ge)
|
|
__s_tmp=(\[ "$__s_value" "$@" ]); "${__s_tmp[@]}"; return $?;;
|
|
-n|-z) __s_tmp=(\[ "$1" "$__s_value" ]); "${__s_tmp[@]}"; return $?;;
|
|
+#*) eval '__s_value="'"${1#+#}"'$__s_value"';;
|
|
-#*) eval '__s_value="${__s_value'"${1#-}"'}"';;
|
|
+%*) eval '__s_value="$__s_value"'"${1#+%}";;
|
|
+*) eval '__s_value="$__s_value"'"${1#+}";;
|
|
-%*) eval '__s_value="${__s_value'"${1#-}"'}"';;
|
|
-*) eval '__s_value="${__s_value%'"${1#-}"'}"';;
|
|
mid|strmid) eval '__s_value="$(strmid "$2" "$__s_value")"'; shift;;
|
|
repl|strrepl) eval '__s_value="$(strrepl "$2" "$3" "$__s_value")"'; shift; shift;;
|
|
*) echo 1>&2 "strops: unknown operator: $1";;
|
|
esac
|
|
shift
|
|
done
|
|
echo "$__s_value"
|
|
}
|
|
|
|
function first_char() {
|
|
# retourner le premier caractère de la chaine $*
|
|
local str="$*"
|
|
echo "${str:0:1}"
|
|
}
|
|
function last_char() {
|
|
# retourner le dernier caractère de la chaine $*
|
|
local str="$*"
|
|
echo "${str: -1:1}"
|
|
}
|
|
function first_chars() {
|
|
# retourner tous les caractères de la chaine $*, excepté le dernier
|
|
local str="$*"
|
|
recho "${str:0:$((${#1}-1))}"
|
|
}
|
|
function last_chars() {
|
|
# retourner tous les caractères de la chaine $*, excepté le premier
|
|
local str="$*"
|
|
recho "${str:1}"
|
|
}
|
|
function first_char_is() {
|
|
# Tester si le premier caractère de la chaine $1 est $2
|
|
[ "${1:0:1}" == "$2" ]
|
|
}
|
|
function last_char_is() {
|
|
# Tester si le dernier caractère de la chaine $1 est $2
|
|
[ "${1:$((-1)):1}" == "$2" ]
|
|
}
|
|
function beginswith() {
|
|
# Tester si la chaine $1 commence par le wildcard $2
|
|
local str="$1" pattern="$2"
|
|
eval '[ "${str#$pattern}" != "$str" ]'
|
|
}
|
|
function endswith() {
|
|
# Tester si la chaine $1 se termine par le wildcard $2
|
|
local str="$1" pattern="$2"
|
|
eval '[ "${str%$pattern}" != "$str" ]'
|
|
}
|
|
|
|
function strsplitf() {
|
|
# Cette fonction doit être appelée avec N arguments (avec N>1). Elle analyse et
|
|
# découpe l'argument $N comme avec une ligne de commande du shell. Ensuite, elle
|
|
# appelle la fonction $1 avec les arguments de $2 à ${N-1}, suivi des arguments
|
|
# obtenus lors de l'analyse de l'argument $N. Par exemple, la commande suivante:
|
|
# strsplitf cmd arg1 "long arg2" "arg3 'long arg4'"
|
|
# est équivalente à:
|
|
# cmd arg1 "long arg2" arg3 "long arg4"
|
|
# Retourner le code 127 si la fonction à appeler n'est pas spécifiée. Retourner
|
|
# le code 126 si une erreur s'est produite lors de l'analyse de l'argument $N
|
|
[ $# -gt 0 ] || return 127
|
|
local func count
|
|
func="$1"; shift
|
|
count=$#
|
|
if [ $count -gt 0 ]; then
|
|
eval 'set -- "${@:1:$(($count-1))}" '"${!count}" || return 126
|
|
fi
|
|
"$func" "$@"
|
|
}
|
|
function strecho() { recho "$@"; }
|
|
function strqvals() {
|
|
# Afficher chaque argument à part avec des quotes. A chainer avec strsplitf()
|
|
qvals "$@"
|
|
}
|
|
function strqlines() {
|
|
# Afficher chaque ligne des fichiers spécifiés comme un argument. A chainer avec
|
|
# strsplitf()
|
|
local -a lines
|
|
_setax lines cat "$@"
|
|
qvals "${lines[@]}"
|
|
}
|
|
function strqarray() {
|
|
# Afficher chaque valeur des tableaux $@ comme un argument. A chainer avec
|
|
# strsplitf()
|
|
local __a __s="qvals"
|
|
for __a in "$@"; do __s="$__s \"\${$__a[@]}\""; done
|
|
eval "$__s"
|
|
}
|
|
|
|
function evals() {
|
|
# Enchainer des traitements sur des chaines de caractères, comme pour la fonction
|
|
# evalx(). Il y a cependant quelques différences:
|
|
# - Seules certains fonctions spécifiques peuvent être utilisées: elles sont
|
|
# reconnaissables à leur préfixe 'str'. En effet, lors de l'utilisation d'une
|
|
# commande par evals(), le préfixe 'str' est systématiquement ajouté.
|
|
# - La fonction strsplitf() est traitée de façon particulière pour lancer une
|
|
# commande avec le préfixe 'str'
|
|
# Ainsi, la commande suivante:
|
|
# evals cmd1 // splitf cmd2
|
|
# est équivalente à la commande:
|
|
# strplitf strcmd2 "$(strcmd1)"
|
|
local __e_val __e_arg __e_r=0
|
|
local __e_firstcmd __e_firstarg __e_splitf
|
|
local -a __e_cmd
|
|
|
|
__e_firstcmd=1
|
|
while [ $# -gt 0 ]; do
|
|
__e_cmd=()
|
|
__e_firstarg=1 # premier argument
|
|
__e_splitf= # premier argument après splitf
|
|
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
|
|
if [ -n "$__e_firstarg" ]; then
|
|
__e_cmd=("str$__e_arg")
|
|
__e_firstarg=
|
|
[ "$__e_arg" == "splitf" ] && __e_splitf=1
|
|
elif [ -n "$__e_splitf" ]; then
|
|
__e_cmd=("${__e_cmd[@]}" "str$__e_arg")
|
|
__e_splitf=
|
|
else
|
|
__e_cmd=("${__e_cmd[@]}" "$__e_arg")
|
|
fi
|
|
done
|
|
|
|
if [ -n "$__e_firstcmd" ]; then
|
|
__e_val="$("${__e_cmd[@]}")" || __e_r=$?
|
|
else
|
|
__e_val="$("${__e_cmd[@]}" "$__e_val")" || __e_r=$?
|
|
fi
|
|
__e_firstcmd=
|
|
done
|
|
[ -n "$__e_val" ] && echo "$__e_val"
|
|
return $__e_r
|
|
}
|