258 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
		
			8.4 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'
 | 
						|
    -t, --title
 | 
						|
    --no-title
 | 
						|
        Afficher (resp. ne pas afficher) chaque correspondance avant de lancer
 | 
						|
        la commande. Par défaut, l'affichage est effectué."
 | 
						|
}
 | 
						|
 | 
						|
basedir=
 | 
						|
match=auto
 | 
						|
changedir=
 | 
						|
parentdir=
 | 
						|
expand=1
 | 
						|
title=1
 | 
						|
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=
 | 
						|
    -t,--title title=1
 | 
						|
    --no-title title=
 | 
						|
)
 | 
						|
parse_args "$@"; set -- "${args[@]}"
 | 
						|
 | 
						|
if [ "$match" == auto ]; then
 | 
						|
    if [ -n "$changedir" ]; then
 | 
						|
        match=dir
 | 
						|
    else
 | 
						|
        match=all
 | 
						|
    fi
 | 
						|
fi
 | 
						|
 | 
						|
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
 | 
						|
    [ -n "$title" ] && etitle "$item"
 | 
						|
    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
 |