#!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 source "$(dirname -- "$0")/lib/ulib/auto" || exit 1 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 par exemple avec -g, -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) if [ -n "$shortcut" ]; then set -- git status --p "$@" else set -- "$@" -- git status --p fi ;; 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