foreach: ajouter une syntaxe alternative pour lister directement les éléments

This commit is contained in:
Jephté Clain 2016-12-04 17:53:53 +04:00
parent 24a8839fec
commit 6a4e6a7146
2 changed files with 111 additions and 45 deletions

View File

@ -5,11 +5,16 @@ foreach: lancer une commande pour un ensemble d'arguments
USAGE USAGE
foreach [options] [VAR=]expr cmd... foreach [options] [VAR=]expr cmd...
foreach [options] [VAR=]items... -- cmd...
La commande est lancée avec la variable 'VAR', qui vaut par défaut 'item', 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' définie à la valeur courante de l'énumération. De plus, la variable 'index'
reçoit une valeur incrémentale commençant à 0. 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 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 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 absolu du fichier, le nom du fichier, le nom de base sans extension, l'extension
@ -17,22 +22,32 @@ 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, file=/path/to/dir/file.ext, dir=/path/to/dir, name=file.ext, basename=file,
ext=ext, dotext=.ext ext=ext, dotext=.ext
Exemple: Les 3 exemples suivants sont équivalents:
foreach '*.c' cp %item dest/dir foreach '*.c' cp %item dest/dir
Equivalent à:
foreach item='*.c' cp %item dest/dir foreach item='*.c' cp %item dest/dir
foreach *.c -- cp %item dest/dir
OPTIONS OPTIONS
-b, --basedir BASEDIR -b, --basedir BASEDIR
Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du
répertoire courant. répertoire courant.
-d, --dir -d, --dir
Faire la correspondance de l'expression sur les répertoires uniquement
-f, --file -f, --file
Faire la correspondance de l'expression sur les fichier uniquement
-a, --all -a, --all
Faire la correspondance de l'expression sur les répertoires et les -s, --string
fichiers 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':
foreach '*.c' --
alors que celle-ci liste les fichiers qui ont l'extension '.c':
foreach 'item=*.c' --
-p, --parent -p, --parent
Pour chaque fichier/répertoire, se placer dans le répertoire 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 avant de lancer la commande. item est aussi modifié pour ne plus
@ -47,14 +62,12 @@ OPTIONS
la cible, soit '.' pour le répertoire courant, soit le nom du fichier la cible, soit '.' pour le répertoire courant, soit le nom du fichier
dans le répertoire courant. dans le répertoire courant.
Si cette option est mentionnée seule, elle implique --dir Si cette option est mentionnée seule, elle implique --dir
-s, --string
Evaluer l'expression avec la fonction 'eval' du shell.
-x, --expand -x, --expand
-n, --no-expand -n, --no-expand
Reconnaitre et traiter (resp. ne pas reconnaitre) la syntaxe %var dans 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 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 l'écriture d'une ligne de commande. Pour écrire le caractère '%', il
suffit de le double e.g %%item suffit de le doubler e.g %%item
Si l'expansion est désactivée, il faut protéger le caractère $ pour 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: qu'il soit traité, e.g, avec les examples ci-dessus:
foreach -n '*.c' 'cp "$item" dest/dir' foreach -n '*.c' 'cp "$item" dest/dir'

125
foreach
View File

@ -8,11 +8,16 @@ function display_help() {
USAGE USAGE
$scriptname [options] [VAR=]expr cmd... $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', 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' définie à la valeur courante de l'énumération. De plus, la variable 'index'
reçoit une valeur incrémentale commençant à 0. 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 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 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 absolu du fichier, le nom du fichier, le nom de base sans extension, l'extension
@ -20,22 +25,32 @@ 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, file=/path/to/dir/file.ext, dir=/path/to/dir, name=file.ext, basename=file,
ext=ext, dotext=.ext ext=ext, dotext=.ext
Exemple: Les 3 exemples suivants sont équivalents:
$scriptname '*.c' cp %item dest/dir $scriptname '*.c' cp %item dest/dir
Equivalent à:
$scriptname item='*.c' cp %item dest/dir $scriptname item='*.c' cp %item dest/dir
$scriptname *.c -- cp %item dest/dir
OPTIONS OPTIONS
-b, --basedir BASEDIR -b, --basedir BASEDIR
Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du Chercher les expressions -d, -f, -a à partir de BASEDIR au lieu du
répertoire courant. répertoire courant.
-d, --dir -d, --dir
Faire la correspondance de l'expression sur les répertoires uniquement
-f, --file -f, --file
Faire la correspondance de l'expression sur les fichier uniquement
-a, --all -a, --all
Faire la correspondance de l'expression sur les répertoires et les -s, --string
fichiers 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 -p, --parent
Pour chaque fichier/répertoire, se placer dans le répertoire 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 avant de lancer la commande. item est aussi modifié pour ne plus
@ -50,14 +65,12 @@ OPTIONS
la cible, soit '.' pour le répertoire courant, soit le nom du fichier la cible, soit '.' pour le répertoire courant, soit le nom du fichier
dans le répertoire courant. dans le répertoire courant.
Si cette option est mentionnée seule, elle implique --dir Si cette option est mentionnée seule, elle implique --dir
-s, --string
Evaluer l'expression avec la fonction 'eval' du shell.
-x, --expand -x, --expand
-n, --no-expand -n, --no-expand
Reconnaitre et traiter (resp. ne pas reconnaitre) la syntaxe %var dans 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 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 l'écriture d'une ligne de commande. Pour écrire le caractère '%', il
suffit de le double e.g %%item suffit de le doubler e.g %%item
Si l'expansion est désactivée, il faut protéger le caractère \$ pour 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: qu'il soit traité, e.g, avec les examples ci-dessus:
$scriptname -n '*.c' 'cp \"\$item\" dest/dir' $scriptname -n '*.c' 'cp \"\$item\" dest/dir'
@ -97,10 +110,58 @@ if [ "$match" == auto ]; then
fi fi
fi fi
alt_syntax=
for sep in "$@"; do
if [ "$sep" == -- ]; then
alt_syntax=1
break
fi
done
suppl_items=()
varexpr="$1"; shift 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 splitfsep2 "$varexpr" = varname expr
[ -n "$varname" ] || varname=item if [ -n "$alt_syntax" ]; then
[ -n "$expr" ] || expr="*" 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=("$@") cmd=("$@")
if [ ${#cmd[*]} -eq 0 ]; then if [ ${#cmd[*]} -eq 0 ]; then
@ -111,33 +172,20 @@ if [ ${#cmd[*]} -eq 0 ]; then
fi fi
fi fi
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
[ -n "$title" ] && einfo "${#items[@]} correspondance(s) trouvée(s)" [ -n "$title" ] && einfo "${#items[@]} correspondance(s) trouvée(s)"
let index=0 let index=0
for item in "${items[@]}"; do for item in "${items[@]}"; do
[ -n "$title" ] && etitle "$item" [ -n "$title" ] && etitle "$item"
i="$item"
setx file=abspath "$item" setx file=abspath "$item"
setx dir=dirname -- "$file" setx dir=dirname -- "$file"
setx name=basename -- "$file" setx name=basename -- "$file"
splitname "$name" basename ext splitname "$name" basename ext
[[ "$name" == *.* ]] && dotext=".$ext" || dotext= [[ "$name" == *.* ]] && dotext=".$ext" || dotext=
export file dir name basename 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 [ -n "$changedir" ]; then
if [ -f "$item" ]; then if [ -f "$item" ]; then
@ -154,13 +202,17 @@ for item in "${items[@]}"; do
cd "$item" cd "$item"
item=. item=.
fi fi
i="$item"
__VALUES=()
for __VALUE in "${__VARS[@]}"; do
array_add __VALUES "$__VALUE=${!__VALUE}"
done
if [ -n "$expand" ]; then if [ -n "$expand" ]; then
array_from_lines cmd "$(awkrun -f \ array_from_lines cmd "$(awkrun -f "${__VALUES[@]}" xitem="$index" item="$item" varname="$varname" cmd[@] '
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) { function replace_vars(src, re, vs, dest) {
re = "(%(file|dir|name|basename|ext|dotext|index|" varname "))" re = "(%(" varname "|i|file|dir|name|basename|ext|dotext|index))"
while (src != "") { while (src != "") {
if (match(src, "%%") != 0) { if (match(src, "%%") != 0) {
dest = dest substr(src, 1, RSTART) dest = dest substr(src, 1, RSTART)
@ -175,14 +227,15 @@ function replace_vars(src, re, vs, dest) {
break break
} }
var = vs[2] var = vs[2]
if (var == "file") dest = dest file 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 == "dir") dest = dest dir
else if (var == "name") dest = dest name else if (var == "name") dest = dest name
else if (var == "basename") dest = dest basename else if (var == "basename") dest = dest basename
else if (var == "ext") dest = dest ext else if (var == "ext") dest = dest ext
else if (var == "dotext") dest = dest dotext else if (var == "dotext") dest = dest dotext
else if (var == "index") dest = dest xitem else if (var == "index") dest = dest xitem
else if (var == varname) dest = dest item
} }
if (src != "") dest = dest src if (src != "") dest = dest src
return dest return dest