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
 |