Cómo extender alias bash

11

¿Cómo crear un alias que realmente extienda otro alias del mismo nombre en Bash?

Por qué:

Solía han GREP_OPTIONSfijado en .bashrcque algo como esto:

GREP_OPTIONS="-I --exclude=\*~"

También tenía un script (digamos setup-java.sh) que llamaría antes de trabajar en algunos proyectos Java. Contendría la línea:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=classes"

Si también uso Sass, llamaría a setup-sass.shcuál contiene la línea:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=\*/.sass-cache"

Pero GREP_OPTIONSquedó en desuso y aparentemente la solución estándar es crear un alias o algún script ...

brandizzi
fuente
¿Qué pasa con las funciones bash?
Jakuje
2
Estoy bastante de acuerdo: usar una función es una opción mucho mejor que un alias.
Charles Duffy

Respuestas:

13

Bash almacena los valores de los alias en una matriz llamada BASH_ALIASES :

$ alias foo=bar
$ echo ${BASH_ALIASES[foo]}
bar

Con la expansión de parámetros podemos obtener el último alias establecido (si existe) o el valor predeterminado:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~"

Ahora solo hazlo en setup-java.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~  --exclude-dir=classes"

... y finalmente en setup-sass.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~ --exclude-dir=\*/.sass-cache"

Si se llaman las tres líneas, obtenemos lo que queremos:

$ echo ${BASH_ALIASES[grep]:-grep}
grep -I --exclude=\*~ -I --exclude=\*~ --exclude-dir=classes -I --exclude=\*~ --exclude-dir=\*/.sass-cache
brandizzi
fuente
13

aliases encadena si los terminas con espacios.

alias print='printf %s\\n ' hey='"hello, fine fellow" '
print hey

hello, fine fellow

Puedes escribir guiones completos de esa manera, si estás lo suficientemente loco. De todos modos, si quieres extender un alias, solo asegúrate de que el alias que deseas extender termine en un espacio, y agrega otro.

alias grep='printf "%s " -I --exclude=\*~ '    \
      exdir=' --exclude-dir=classes '          \
      exsass='--exclude-dir=\*/.sass-cache '
grep exdir exsass exdir exsass

-I --exclude=*~ --exclude-dir=classes --exclude-dir=*/.sass-cache --exclude-dir=classes --exclude-dir=*/.sass-cache
mikeserv
fuente
77
Esto es horriblemente hermoso.
user1717828
Wow, esto es asombroso. No sabía esto (y probablemente no lo use mucho, porque creo que va en contra de la Regla de claridad ), ¡pero es bueno saberlo! Pregunta, sin embargo: ¿Por qué el espacio al comienzo de exdir? (¿Es solo por alineación por razones estéticas?)
Comodín el
2
@Wildcard: fnmatch(){ alias fnmatch='case $1 in '; while "${1:+:}" 2>&-; do eval 'fnmatch pattern list ;; esac'; shift; done; unalias fnmatch; }; alias pattern='${1:+*}) ' list=': do stuff '; fnmatch "$@". Hacerlo con le aliasespermite utilizar las expansiones de los patrones de forma más directa y segura. Necesita un segundo contexto evalcuando se lo llama desde una función, pero no es inherentemente inseguro siempre que los nombres patterny listestén controlados por usted. Solo pueden romperse en la mayoría de los casos, incluso cuando no lo están, a menos que algún atacante, a sabiendas, termine correctamente case.
mikeserv
1
Uso este patrón en mi .bashrc:, alias sudo='sudo 'esto me permite llamar a todos mis comandos con alias después de a sudo. Sin el espacio no funcionaría
arainone
1
@Wildcard: no estaba abogando exactamente por ese uso, pero es cierto que puedes, y también es cierto que deberías estar al menos un poco loco para intentarlo.
mikeserv
2

Una función es una mejor opción que un alias extensible aquí.

grep_options=( )
grep() {
  exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"
}

De esa manera, tiene dos opciones para agregar opciones al entorno:

  • Enmendar la grep_optionsmatriz; esto admite correctamente las opciones con espacios, caracteres glob literales y otros casos de esquina:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
  • Use la GREP_OPTIONSvariable escalar tradicional , a pesar de sus dificultades (vea BashFAQ # 50 para comprender algunos de estos):

    GREP_OPTIONS+=' --exclude-dir=classes '

Dicho esto, si desea que sus opciones se reflejen en grepinstancias invocadas fuera del shell, ni un alias ni una función funcionarán. En su lugar, querrá un script de contenedor colocado antes en su RUTA que el grepcomando real . Por ejemplo:

# in ~/.bash_profile
[[ -e ~/bin ]] && PATH=$HOME/bin:$PATH

... y, en ~/bin/grep:

#!/bin/bash

# load overrides to grep_options on GREP_OPTIONS from local dotfiles
source ~/.bash_profile
source ~/.bashrc

# ...and use them:
exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"
Charles Duffy
fuente