302 lines
9.8 KiB
Bash
Executable File
302 lines
9.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
|
|
urequire DEFAULTS
|
|
|
|
function display_help() {
|
|
uecho "$scriptname: lancer une commande pour un ensemble d'arguments
|
|
|
|
USAGE
|
|
$scriptname [options] [VAR=]expr cmd...
|
|
$scriptname [options] [VAR=]items... -- cmd...
|
|
|
|
La commande est lancée avec la variable 'VAR', qui vaut par défaut 'item',
|
|
définie à la valeur courante de l'énumération. De plus, la variable 'index'
|
|
reçoit une valeur incrémentale commençant à 0.
|
|
|
|
La deuxième syntaxe appelée syntaxe alternative permet de spécifier un ensemble
|
|
d'éléments directement, mais nécessite l'utilisation du séparateur '--' pour
|
|
identifier où s'arrête la liste des éléments.
|
|
|
|
En plus de VAR, les variables file, dir, name, basename, ext et dotext sont
|
|
définies. Elle valent respectivement le chemin absolu du fichier, le répertoire
|
|
absolu du fichier, le nom du fichier, le nom de base sans extension, l'extension
|
|
sans le point et l'extension avec le point, e.g pour item=dir/file.ext on a
|
|
file=/path/to/dir/file.ext, dir=/path/to/dir, name=file.ext, basename=file,
|
|
ext=ext, dotext=.ext
|
|
|
|
Les 3 exemples suivants sont équivalents:
|
|
$scriptname '*.c' cp %item dest/dir
|
|
$scriptname item='*.c' cp %item dest/dir
|
|
$scriptname *.c -- cp %item dest/dir
|
|
|
|
OPTIONS
|
|
-b, --basedir BASEDIR
|
|
Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du
|
|
répertoire courant.
|
|
-d, --dir
|
|
-f, --file
|
|
-a, --all
|
|
-s, --string
|
|
Ces options permettent de spécifier le type d'expression et la façon de
|
|
les traiter. Avec -d, faire la correspondance de l'expression sur les
|
|
répertoires uniquement. Avec -f, faire la correspondance sur les fichier
|
|
uniquement. Avec -a, faire la correspondance sur les répertoires et les
|
|
fichiers. Avec -s, évaluer l'expression avec la fonction 'eval' du
|
|
shell.
|
|
Si la syntaxe alternative est utilisée, le premier élément est évalué
|
|
conformément à ces options *si et seulement s'il* est précédé d'une
|
|
chaine 'VAR='. Les autres éléments sont pris tels-quels. e.g:
|
|
cette commande affiche uniquement la chaine '*.c':
|
|
$scriptname '*.c' --
|
|
alors que celle-ci liste les fichiers qui ont l'extension '.c':
|
|
$scriptname 'item=*.c' --
|
|
-p, --parent
|
|
Pour chaque fichier/répertoire, se placer dans le répertoire parent
|
|
avant de lancer la commande. item est aussi modifié pour ne plus
|
|
contenir que le nom de la cible (qui est désormais dans le répertoire
|
|
courant)
|
|
Cette option a la priorité sur --go
|
|
-g, --go
|
|
Si la cible est un répertoire, en faire le répertoire courant avant de
|
|
lancer la commande. Si la cible est un fichier, faire comme --parent et
|
|
se placer dans le répertoire du fichier avant de lancer la commande.
|
|
Dans les deux cas, item est modifié pour ne plus contenir que le nom de
|
|
la cible, soit '.' pour le répertoire courant, soit le nom du fichier
|
|
dans le répertoire courant.
|
|
Si cette option est mentionnée seule, elle implique --dir
|
|
-x, --expand
|
|
-n, --no-expand
|
|
Reconnaitre et traiter (resp. ne pas reconnaitre) la syntaxe %var dans
|
|
les arguments. C'est le cas par défaut, ce qui permet de simplifier
|
|
l'écriture d'une ligne de commande. Pour écrire le caractère '%', il
|
|
suffit de le doubler e.g %%item
|
|
Si l'expansion est désactivée, il faut protéger le caractère \$ pour
|
|
qu'il soit traité, e.g, avec les examples ci-dessus:
|
|
$scriptname -n '*.c' 'cp \"\$item\" dest/dir'
|
|
--title
|
|
--pt, --parent-title
|
|
--nt, --no-title
|
|
Afficher (resp. ne pas afficher) chaque correspondance avant de lancer
|
|
la commande. Par défaut, l'affichage est effectué.
|
|
Avec --parent-title, pour chaque correspondance afficher plutôt le
|
|
répertoire parent (valide uniquement avec l'option -p)
|
|
-S, --git-status
|
|
Equivalent à spécifier la commande 'git status --p'
|
|
Utiliser avec -G ou -C
|
|
-G, --git-projects
|
|
Equivalent à '--ptitle -p */.git --' e.g '$scriptname -G git pull' pour
|
|
mettre à jour les dépôts situés dans un répertoire
|
|
-C, --composer-projects
|
|
Equivalent à '--ptitle -p */composer.json --'
|
|
--cc, --composer-cmd
|
|
Equivalent à '--ptitle -p */composer.json -- dk composer'"
|
|
}
|
|
|
|
basedir=
|
|
match=auto
|
|
changedir=
|
|
parentdir=
|
|
expand=1
|
|
title=auto
|
|
command=
|
|
shortcut=
|
|
args=(+
|
|
--help '$exit_with display_help'
|
|
-b:,--basedir: basedir=
|
|
-d,--dir match=dir
|
|
-f,-file match=file
|
|
-a,--all match=all
|
|
-p,--parent parentdir=1
|
|
-g,--go changedir=1
|
|
-s,--string match=string
|
|
-x,--expand expand=1
|
|
-n,--no-expand expand=
|
|
--title title=1
|
|
--pt,--parent-title title=p
|
|
--nt,--no-title title=
|
|
-S,--git-status command=git-status-p
|
|
-G,--git-projects shortcut=git
|
|
-C,--composer-projects shortcut=composer
|
|
--cc,--composer-cmd shortcut=composer-cmd
|
|
)
|
|
parse_args "$@"; set -- "${args[@]}"
|
|
|
|
case "$command" in
|
|
git-status-p)
|
|
set -- git status --p "$@"
|
|
;;
|
|
esac
|
|
case "$shortcut" in
|
|
git)
|
|
set -- */.git -- "$@"
|
|
parentdir=1
|
|
[ "$title" == auto ] && title=p
|
|
;;
|
|
composer)
|
|
set -- */composer.json -- "$@"
|
|
parentdir=1
|
|
[ "$title" == auto ] && title=p
|
|
;;
|
|
composer-cmd)
|
|
set -- */composer.json -- "$scriptdir/dk" composer "$@"
|
|
parentdir=1
|
|
[ "$title" == auto ] && title=p
|
|
;;
|
|
esac
|
|
|
|
if [ "$match" == auto ]; then
|
|
[ -n "$changedir" ] && match=dir || match=all
|
|
fi
|
|
[ "$title" == auto ] && title=1
|
|
|
|
alt_syntax=
|
|
for sep in "$@"; do
|
|
if [ "$sep" == -- ]; then
|
|
alt_syntax=1
|
|
break
|
|
fi
|
|
done
|
|
suppl_items=()
|
|
varexpr="$1"; shift
|
|
if [ -n "$alt_syntax" ]; then
|
|
while [ $# -gt 0 ]; do
|
|
[ "$1" == -- ] && break
|
|
array_add suppl_items "$1"
|
|
shift
|
|
done
|
|
[ "$1" == -- ] && shift
|
|
fi
|
|
splitfsep2 "$varexpr" = varname expr
|
|
if [ -n "$alt_syntax" ]; then
|
|
if [ -n "$varname" ]; then
|
|
[ -n "$expr" ] || expr="*"
|
|
elif [[ "$varexpr" == *=* ]]; then
|
|
[ -n "$varname" ] || varname=item
|
|
[ -n "$expr" ] || expr="*"
|
|
else
|
|
items=("$varexpr")
|
|
varname=item
|
|
expr=
|
|
fi
|
|
else
|
|
[ -n "$varname" ] || varname=item
|
|
[ -n "$expr" ] || expr="*"
|
|
fi
|
|
if [ -n "$expr" ]; then
|
|
if [ -n "$basedir" ]; then
|
|
case "$match" in
|
|
all) array_lsall items "$basedir" "$expr";;
|
|
dir) array_lsdirs items "$basedir" "$expr";;
|
|
file) array_lsfiles items "$basedir" "$expr";;
|
|
string) eval "items=($expr)";;
|
|
esac
|
|
else
|
|
basedir=.
|
|
case "$match" in
|
|
all) array_from_lines items "$(list_all "$basedir" "$expr")";;
|
|
dir) array_from_lines items "$(list_dirs "$basedir" "$expr")";;
|
|
file) array_from_lines items "$(list_files "$basedir" "$expr")";;
|
|
string) eval "items=($expr)";;
|
|
esac
|
|
fi
|
|
fi
|
|
array_extend items suppl_items
|
|
|
|
cmd=("$@")
|
|
if [ ${#cmd[*]} -eq 0 ]; then
|
|
if [ -n "$expand" ]; then
|
|
cmd=(echo %item)
|
|
else
|
|
cmd=('echo "$item"')
|
|
fi
|
|
fi
|
|
|
|
[ -n "$title" ] && einfo "${#items[@]} correspondance(s) trouvée(s)"
|
|
let index=0
|
|
for item in "${items[@]}"; do
|
|
if [ -n "$parentdir" -a "$title" == p ]; then
|
|
etitle "$(dirname -- "$item")"
|
|
elif [ -n "$title" ]; then
|
|
etitle "$item"
|
|
fi
|
|
i="$item"
|
|
setx file=abspath "$item"
|
|
setx dir=dirname -- "$file"
|
|
setx name=basename -- "$file"
|
|
splitname "$name" basename ext
|
|
[[ "$name" == *.* ]] && dotext=".$ext" || dotext=
|
|
# ne pas changer les noms des variables sans modifier le script awk
|
|
# ci-dessous
|
|
__VARS=(i file dir name basename ext dotext)
|
|
export "${__VARS[@]}"
|
|
(
|
|
if [ -n "$changedir" ]; then
|
|
if [ -f "$item" ]; then
|
|
parentdir=1
|
|
elif [ ! -d "$item" ]; then
|
|
ewarn "$item: n'est pas un répertoire"
|
|
changedir=
|
|
fi
|
|
fi
|
|
if [ -n "$parentdir" ]; then
|
|
cd "$dir"
|
|
item="$name"
|
|
elif [ -n "$changedir" ]; then
|
|
cd "$item"
|
|
item=.
|
|
fi
|
|
i="$item"
|
|
|
|
__VALUES=()
|
|
for __VALUE in "${__VARS[@]}"; do
|
|
array_add __VALUES "$__VALUE=${!__VALUE}"
|
|
done
|
|
|
|
if [ -n "$expand" ]; then
|
|
array_from_lines cmd "$(awkrun -f "${__VALUES[@]}" xitem="$index" item="$item" varname="$varname" cmd[@] '
|
|
function replace_vars(src, re, vs, dest) {
|
|
re = "(%(" varname "|i|file|dir|name|basename|ext|dotext|index))"
|
|
while (src != "") {
|
|
if (match(src, "%%") != 0) {
|
|
dest = dest substr(src, 1, RSTART)
|
|
src = substr(src, RSTART + RLENGTH)
|
|
} else if (match(src, "%" re) != 0) {
|
|
dest = dest substr(src, 1, RSTART)
|
|
src = substr(src, RSTART + RLENGTH)
|
|
} else if (match(src, re, vs) != 0) {
|
|
dest = dest substr(src, 1, RSTART - 1)
|
|
src = substr(src, RSTART + RLENGTH)
|
|
} else {
|
|
break
|
|
}
|
|
var = vs[2]
|
|
if (var == varname) dest = dest item
|
|
else if (var == "i") dest = dest item
|
|
else if (var == "file") dest = dest file
|
|
else if (var == "dir") dest = dest dir
|
|
else if (var == "name") dest = dest name
|
|
else if (var == "basename") dest = dest basename
|
|
else if (var == "ext") dest = dest ext
|
|
else if (var == "dotext") dest = dest dotext
|
|
else if (var == "index") dest = dest xitem
|
|
}
|
|
if (src != "") dest = dest src
|
|
return dest
|
|
}
|
|
BEGIN {
|
|
for (i=1; i<=cmd_count; i++) {
|
|
arg = replace_vars(cmd[i])
|
|
print arg
|
|
}
|
|
}')"
|
|
eval "export $(echo_setv "$varname" "$item")"
|
|
"${cmd[@]}"
|
|
else
|
|
eval "export $(echo_setv "$varname" "$item"); ${cmd[*]}"
|
|
fi
|
|
)
|
|
[ -n "$title" ] && eend "$item"
|
|
let index=$index+1
|
|
done
|