459 lines
13 KiB
Bash
459 lines
13 KiB
Bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
##@cooked nocomments
|
|
module: base.core base_ "Fonctions de base: fondement"
|
|
|
|
function: echo_ "afficher la valeur \$* sans passer à la ligne"
|
|
function echo_() { 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)"
|
|
function recho() {
|
|
if [[ "${1:0:2}" == -[eEn] ]]; then
|
|
local first="${1:1}"; shift
|
|
echo -n -
|
|
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)"
|
|
function recho_() {
|
|
if [[ "${1:0:2}" == -[eEn] ]]; then
|
|
local first="${1:1}"; shift
|
|
echo -n -
|
|
echo -n "$first" "$@"
|
|
else
|
|
echo -n "$@"
|
|
fi
|
|
}
|
|
|
|
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"
|
|
function _qval() {
|
|
local s="$*"
|
|
s="${s//\\/\\\\}"
|
|
s="${s//\"/\\\"}"
|
|
s="${s//\$/\\\$}"
|
|
s="${s//\`/\\\`}"
|
|
recho_ "$s"
|
|
}
|
|
|
|
function: base_should_quote "Tester si la chaine \$* doit être mise entre quotes"
|
|
function base_should_quote() {
|
|
# pour optimiser, toujours mettre entre quotes si plusieurs arguments sont
|
|
# spécifiés ou si on spécifie une chaine vide ou de plus de 80 caractères
|
|
[ $# -eq 0 -o $# -gt 1 -o ${#1} -eq 0 -o ${#1} -gt 80 ] && return 0
|
|
# sinon, tester si la chaine contient des caractères spéciaux
|
|
local s="$*"
|
|
s="${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 \""
|
|
function qval() {
|
|
echo -n \"
|
|
_qval "$@"
|
|
echo \"
|
|
}
|
|
|
|
function: qvalm "Afficher la chaine \$* quotée si nécessaire avec \""
|
|
function qvalm() {
|
|
if base_should_quote "$@"; then
|
|
echo -n \"
|
|
_qval "$@"
|
|
echo \"
|
|
else
|
|
recho "$@"
|
|
fi
|
|
}
|
|
|
|
function: qvalr "Afficher la chaine \$* quotée si nécessaire avec \", sauf si elle est vide"
|
|
function qvalr() {
|
|
if [ -z "$*" ]; then
|
|
:
|
|
elif base_should_quote "$@"; then
|
|
echo -n \"
|
|
_qval "$@"
|
|
echo \"
|
|
else
|
|
recho "$@"
|
|
fi
|
|
}
|
|
|
|
function: qvals "Afficher chaque argument de cette fonction quotée le cas échéant avec \", chaque valeur étant séparée par un espace"
|
|
function qvals() {
|
|
local arg first=1
|
|
for arg in "$@"; do
|
|
[ -z "$first" ] && echo -n " "
|
|
if base_should_quote "$arg"; then
|
|
echo -n \"
|
|
_qval "$arg"
|
|
echo -n \"
|
|
else
|
|
recho_ "$arg"
|
|
fi
|
|
first=
|
|
done
|
|
[ -z "$first" ] && echo
|
|
}
|
|
|
|
function: qwc "Dans la chaine \$*, remplacer:
|
|
~~~
|
|
\\ par \\\\
|
|
\" par \\\"
|
|
\$ par \\\$
|
|
\` par \\\`
|
|
~~~
|
|
puis quoter la chaine avec \", sauf les wildcards *, ? et [class]
|
|
|
|
Cela permet de quoter une chaine permettant de glober des fichiers, e.g
|
|
~~~
|
|
eval \"ls \$(qwc \"\$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"
|
|
function qwc() {
|
|
local s="$*"
|
|
s="${s//\\/\\\\}"
|
|
s="${s//\"/\\\"}"
|
|
s="${s//\$/\\\$}"
|
|
s="${s//\`/\\\`}"
|
|
local r a b c
|
|
while [ -n "$s" ]; do
|
|
a=; b=; c=
|
|
a=; [[ "$s" == *\** ]] && { a="${s%%\**}"; a=${#a}; }
|
|
b=; [[ "$s" == *\?* ]] && { b="${s%%\?*}"; b=${#b}; }
|
|
c=; [[ "$s" == *\[* ]] && { c="${s%%\[*}"; c=${#c}; }
|
|
if [ -z "$a" -a -z "$b" -a -z "$c" ]; then
|
|
r="$r\"$s\""
|
|
break
|
|
fi
|
|
if [ -n "$a" ]; then
|
|
[ -n "$b" ] && [ $a -lt $b ] && b=
|
|
[ -n "$c" ] && [ $a -lt $c ] && c=
|
|
fi
|
|
if [ -n "$b" ]; then
|
|
[ -n "$a" ] && [ $b -lt $a ] && a=
|
|
[ -n "$c" ] && [ $b -lt $c ] && c=
|
|
fi
|
|
if [ -n "$c" ]; then
|
|
[ -n "$a" ] && [ $c -lt $a ] && a=
|
|
[ -n "$b" ] && [ $c -lt $b ] && b=
|
|
fi
|
|
if [ -n "$a" ]; then # PREFIX*
|
|
a="${s%%\**}"
|
|
s="${s#*\*}"
|
|
[ -n "$a" ] && r="$r\"$a\""
|
|
r="$r*"
|
|
elif [ -n "$b" ]; then # PREFIX?
|
|
a="${s%%\?*}"
|
|
s="${s#*\?}"
|
|
[ -n "$a" ] && r="$r\"$a\""
|
|
r="$r?"
|
|
elif [ -n "$c" ]; then # PREFIX[class]
|
|
a="${s%%\[*}"
|
|
b="${s#*\[}"; b="${b%%\]*}"
|
|
s="${s:$((${#a} + ${#b} + 2))}"
|
|
[ -n "$a" ] && r="$r\"$a\""
|
|
r="$r[$b]"
|
|
fi
|
|
done
|
|
recho_ "$r"
|
|
}
|
|
|
|
function: qlines "Traiter chaque ligne de l'entrée standard pour en faire des chaines quotées avec '"
|
|
function qlines() {
|
|
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"
|
|
function setv() {
|
|
local s__var="$1"; shift
|
|
if [[ "$s__var" == *=* ]]; then
|
|
set -- "${s__var#*=}" "$@"
|
|
s__var="${s__var%%=*}"
|
|
fi
|
|
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()"
|
|
function _setv() {
|
|
local s__var="$1"; shift
|
|
eval "$s__var=\"\$*\""
|
|
}
|
|
|
|
function: echo_setv "Afficher la commande qui serait lancée par setv \"\$@\""
|
|
function echo_setv() {
|
|
local s__var="$1"; shift
|
|
if [[ "$s__var" == *=* ]]; then
|
|
set -- "${s__var#*=}" "$@"
|
|
s__var="${s__var%%=*}"
|
|
fi
|
|
echo "$s__var=$(qvalr "$*")"
|
|
}
|
|
|
|
function: echo_setv2 "Afficher la commande qui recrée la variable \$1.
|
|
|
|
Equivalent à
|
|
~~~
|
|
echo_setv \"\$1=\${!1}\"
|
|
~~~
|
|
|
|
Si d'autres arguments que le nom de la variable sont spécifiés, cette fonction
|
|
se comporte comme echo_setv()"
|
|
function echo_setv2() {
|
|
local s__var="$1"; shift
|
|
if [[ "$s__var" == *=* ]]; then
|
|
set -- "${s__var#*=}" "$@"
|
|
s__var="${s__var%%=*}"
|
|
fi
|
|
if [ $# -eq 0 ]; then
|
|
echo_setv "$s__var" "${!s__var}"
|
|
else
|
|
echo_setv "$s__var" "$@"
|
|
fi
|
|
}
|
|
|
|
function: seta "initialiser le tableau \$1 avec les valeurs \$2..@
|
|
|
|
note: en principe, la syntaxe est 'seta array values...'. cependant, la syntaxe
|
|
'seta array=values...' est supportée aussi"
|
|
function seta() {
|
|
local s__array="$1"; shift
|
|
if [[ "$s__array" == *=* ]]; then
|
|
set -- "${s__array#*=}" "$@"
|
|
s__array="${s__array%%=*}"
|
|
fi
|
|
eval "$s__array=(\"\$@\")"
|
|
}
|
|
|
|
function: _seta "Comme la fonction seta() mais ne supporte que la syntaxe '_seta array values...'
|
|
|
|
Cette fonction est légèrement plus rapide que seta()"
|
|
function _seta() {
|
|
local s__array="$1"; shift
|
|
eval "$s__array=(\"\$@\")"
|
|
}
|
|
|
|
function: echo_seta "Afficher la commande qui serait lancée par seta \"\$@\""
|
|
function echo_seta() {
|
|
local s__var="$1"; shift
|
|
if [[ "$s__var" == *=* ]]; then
|
|
set -- "${s__var#*=}" "$@"
|
|
s__var="${s__var%%=*}"
|
|
fi
|
|
echo "$s__var=($(qvals "$@"))"
|
|
}
|
|
|
|
function: echo_seta2 "Afficher la commande qui recrée le tableau \$1
|
|
|
|
Si d'autres arguments que le nom de tableau sont spécifiés, cette fonction se
|
|
comporte comme echo_seta()"
|
|
function echo_seta2() {
|
|
local s__var="$1"; shift
|
|
if [[ "$s__var" == *=* ]]; then
|
|
set -- "${s__var#*=}" "$@"
|
|
s__var="${s__var%%=*}"
|
|
elif [ $# -eq 0 ]; then
|
|
eval "set -- \"\${$s__var[@]}\""
|
|
fi
|
|
echo "$s__var=($(qvals "$@"))"
|
|
}
|
|
|
|
function: setx "Initialiser une variable avec le résultat d'une commande
|
|
|
|
* syntaxe 1: initialiser la variable \$1 avec le résultat de la commande \"\$2..@\"
|
|
~~~
|
|
setx var cmd
|
|
~~~
|
|
note: en principe, la syntaxe est 'setx var cmd args...'. cependant, la syntaxe
|
|
'setx var=cmd args...' est supportée aussi
|
|
|
|
* syntaxe 2: initialiser le tableau \$1 avec le résultat de la commande
|
|
\"\$2..@\", chaque ligne du résultat étant un élément du tableau
|
|
~~~
|
|
setx -a array cmd
|
|
~~~
|
|
note: en principe, la syntaxe est 'setx -a array cmd args...'. cependant, la
|
|
syntaxe 'setx -a array=cmd args...' est supportée aussi"
|
|
function setx() {
|
|
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."
|
|
function _setvx() {
|
|
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."
|
|
function _setax() {
|
|
local s__array="$1"; shift
|
|
eval "$s__array=($("$@" | qlines))"
|
|
}
|
|
|
|
function: base_is_defined "tester si la variable \$1 est définie"
|
|
function base_is_defined() {
|
|
[ -n "$(declare -p "$1" 2>/dev/null)" ]
|
|
}
|
|
|
|
function: base_is_array "tester si la variable \$1 est un tableau"
|
|
function base_is_array() {
|
|
[[ "$(declare -p "$1" 2>/dev/null)" =~ declare\ -[^\ ]*a[^\ ]*\ ]]
|
|
}
|
|
|
|
function: base_array_local "afficher les commandes pour faire une copie dans la variable locale \$1 du tableau \$2"
|
|
function base_array_local() {
|
|
if [ "$1" == "$2" ]; then
|
|
declare -p "$1" 2>/dev/null || echo "local -a $1"
|
|
else
|
|
echo "local -a $1; $1=(\"\${$2[@]}\")"
|
|
fi
|
|
}
|
|
|
|
function: base_upvar "Implémentation de upvar() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
|
|
|
|
USAGE
|
|
~~~
|
|
local varname && base_upvar varname values...
|
|
~~~
|
|
* @param varname Variable name to assign value to
|
|
* @param values Value(s) to assign. If multiple values (> 1), an array is
|
|
assigned, otherwise a single value is assigned."
|
|
function base_upvar() {
|
|
if unset -v "$1"; then
|
|
if [ $# -lt 2 ]; then
|
|
eval "$1=\"\$2\""
|
|
else
|
|
eval "$1=(\"\${@:2}\")"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function: base_array_upvar "Comme base_upvar() mais force la création d'un tableau, même s'il y a que 0 ou 1 argument"
|
|
function base_array_upvar() {
|
|
unset -v "$1" && eval "$1=(\"\${@:2}\")"
|
|
}
|
|
|
|
function: base_upvars "Implémentation modifiée de upvars() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
|
|
|
|
Par rapport à l'original, il n'est plus nécessaire de préfixer une variable
|
|
scalaire avec -v, et -a peut être spécifié sans argument.
|
|
|
|
USAGE
|
|
~~~
|
|
local varnames... && base_upvars [varname value | -aN varname values...]...
|
|
~~~
|
|
* @param -a assigns remaining values to varname as array
|
|
* @param -aN assigns next N values to varname as array. Returns 1 if wrong
|
|
number of options occurs"
|
|
function base_upvars() {
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
-a)
|
|
unset -v "$2" && eval "$2=(\"\${@:3}\")"
|
|
break
|
|
;;
|
|
-a*)
|
|
unset -v "$2" && eval "$2=(\"\${@:3:${1#-a}}\")"
|
|
shift $((${1#-a} + 2)) || return 1
|
|
;;
|
|
*)
|
|
unset -v "$1" && eval "$1=\"\$2\""
|
|
shift; shift
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function: base_set_debug "Passer en mode DEBUG"
|
|
function base_set_debug() {
|
|
export NULIB_DEBUG=1
|
|
}
|
|
|
|
function: base_is_debug "Tester si on est en mode DEBUG"
|
|
function base_is_debug() {
|
|
[ -n "$NULIB_DEBUG" ]
|
|
}
|
|
|
|
function: lawk "Lancer GNUawk avec la librairie 'base'"
|
|
function lawk() {
|
|
gawk -i base "$@"
|
|
}
|
|
|
|
function: cawk "Lancer GNUawk avec LANG=C et la librairie 'base'
|
|
|
|
Le fait de forcer la valeur de LANG permet d'éviter les problèmes avec la locale"
|
|
function cawk() {
|
|
LANG=C gawk -i base "$@"
|
|
}
|
|
|
|
function: lsort "Lancer sort avec support de la locale courante"
|
|
function: csort "Lancer sort avec LANG=C pour désactiver le support de la locale
|
|
|
|
Avec LANG!=C, sort utilise les règles de la locale pour le tri, et par
|
|
exemple, avec LANG=fr_FR.UTF-8, la locale indique que les ponctuations doivent
|
|
être ignorées."
|
|
function lsort() { sort "$@"; }
|
|
function csort() { LANG=C sort "$@"; }
|
|
|
|
function: lgrep "Lancer grep avec support de la locale courante"
|
|
function: cgrep "Lancer grep avec LANG=C pour désactiver le support de la locale"
|
|
function lgrep() { grep "$@"; }
|
|
function cgrep() { LANG=C grep "$@"; }
|
|
|
|
function: lsed "Lancer sed avec support de la locale courante"
|
|
function: csed "Lancer sed avec LANG=C pour désactiver le support de la locale"
|
|
function lsed() { sed "$@"; }
|
|
function csed() { LANG=C sed "$@"; }
|
|
|
|
function: ldiff "Lancer diff avec support de la locale courante"
|
|
function: cdiff "Lancer diff avec LANG=C pour désactiver le support de la locale"
|
|
function ldiff() { diff "$@"; }
|
|
function cdiff() { LANG=C diff "$@"; }
|