nutools/foreach

205 lines
6.6 KiB
Plaintext
Raw Permalink Normal View History

2016-06-07 02:06:59 +04:00
#!/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...
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.
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
2016-06-07 02:06:59 +04:00
Exemple:
$scriptname '*.c' cp %item dest/dir
2016-07-28 16:36:13 +04:00
Equivalent à:
$scriptname item='*.c' cp %item dest/dir
2016-06-07 02:06:59 +04:00
OPTIONS
-b, --basedir BASEDIR
2016-06-13 08:18:37 +04:00
Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du
2016-06-07 02:06:59 +04:00
répertoire courant.
-d, --dir
2016-06-13 08:18:37 +04:00
Faire la correspondance de l'expression sur les répertoires uniquement
2016-06-07 02:06:59 +04:00
-f, --file
2016-06-13 08:18:37 +04:00
Faire la correspondance de l'expression sur les fichier uniquement
2016-06-07 02:06:59 +04:00
-a, --all
2016-06-13 08:18:37 +04:00
Faire la correspondance de l'expression sur les répertoires et les
fichiers
-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
2016-06-07 02:06:59 +04:00
-s, --string
Evaluer l'expression avec la fonction 'eval' du shell.
-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 double 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'
2016-06-08 12:34:22 +04:00
-t, --title
--no-title
Afficher (resp. ne pas afficher) chaque correspondance avant de lancer
la commande. Par défaut, l'affichage est effectué."
2016-06-07 02:06:59 +04:00
}
basedir=
2016-06-13 08:18:37 +04:00
match=auto
2016-06-07 02:06:59 +04:00
changedir=
2016-06-13 08:18:37 +04:00
parentdir=
expand=1
2016-06-08 12:34:22 +04:00
title=1
2016-06-07 02:06:59 +04:00
args=(+
--help '$exit_with display_help'
-b:,--basedir: basedir=
-d,--dir match=dir
-f,-file match=file
-a,--all match=all
2016-06-13 08:18:37 +04:00
-p,--parent parentdir=1
-g,--go changedir=1
2016-06-07 02:06:59 +04:00
-s,--string match=string
-x,--expand expand=1
-n,--no-expand expand=
2016-06-08 12:34:22 +04:00
-t,--title title=1
--no-title title=
2016-06-07 02:06:59 +04:00
)
parse_args "$@"; set -- "${args[@]}"
2016-06-13 08:18:37 +04:00
if [ "$match" == auto ]; then
if [ -n "$changedir" ]; then
match=dir
else
match=all
fi
fi
2016-06-07 02:06:59 +04:00
varexpr="$1"; shift
splitfsep2 "$varexpr" = varname expr
[ -n "$varname" ] || varname=item
[ -n "$expr" ] || expr="*"
cmd=("$@")
if [ ${#cmd[*]} -eq 0 ]; then
if [ -n "$expand" ]; then
cmd=(echo %item)
else
cmd=('echo "$item"')
fi
fi
2016-06-07 02:06:59 +04:00
if [ -n "$basedir" ]; then
case "$match" in
2016-06-07 02:06:59 +04:00
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
2016-06-07 02:06:59 +04:00
2016-06-08 12:34:22 +04:00
[ -n "$title" ] && einfo "${#items[@]} correspondance(s) trouvée(s)"
2016-06-07 02:06:59 +04:00
let index=0
for item in "${items[@]}"; do
2016-06-08 12:34:22 +04:00
[ -n "$title" ] && etitle "$item"
setx file=abspath "$item"
setx dir=dirname -- "$file"
setx name=basename -- "$file"
splitname "$name" basename ext
[[ "$name" == *.* ]] && dotext=".$ext" || dotext=
export file dir name basename ext dotext
2016-06-07 02:06:59 +04:00
(
2016-06-13 08:18:37 +04:00
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"
2016-06-13 08:18:37 +04:00
elif [ -n "$changedir" ]; then
cd "$item"
item=.
fi
if [ -n "$expand" ]; then
array_from_lines cmd "$(awkrun -f \
file="$file" dir="$dir" name="$name" basename="$basename" ext="$ext" dotext="$dotext" \
xitem="$index" item="$item" varname="$varname" cmd[@] \
'
function replace_vars(src, re, vs, dest) {
re = "(%(file|dir|name|basename|ext|dotext|index|" varname "))"
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 == "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
else if (var == varname) dest = dest item
}
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
2016-06-07 02:06:59 +04:00
)
2016-06-08 12:34:22 +04:00
[ -n "$title" ] && eend "$item"
2016-06-07 02:06:59 +04:00
let index=$index+1
done