Come estendere gli alias bash


11

Come creare un alias che estende effettivamente un altro alias con lo stesso nome in Bash?

Perché:

Ho usato per avere GREP_OPTIONSimpostato su .bashrca qualcosa di simile:

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

Avevo anche una sceneggiatura (diciamo così setup-java.sh) che avrei chiamato prima di lavorare su alcuni progetti Java. Conterrebbe la riga:

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

Se anche io uso Sass, chiamerei setup-sass.shche contiene la linea:

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

Ma è GREP_OPTIONSstato deprecato e apparentemente la soluzione standard è creare un alias o alcuni script ...


Che dire delle funzioni bash?
Jakuje,

2
Sono abbastanza d'accordo: l'uso di una funzione è un'opzione molto migliore di un alias.
Charles Duffy,

Risposte:


13

Bash memorizza i valori degli alias in un array chiamato BASH_ALIASES :

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

Con l' espansione dei parametri possiamo ottenere l'ultimo alias impostato (se esiste) o il valore predefinito:

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

Ora fallo e basta setup-java.sh:

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

... e infine su setup-sass.sh:

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

Se vengono chiamate le tre linee, otteniamo ciò che vogliamo:

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

13

aliases catena se li finisci con spazi.

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

hello, fine fellow

Puoi scrivere interi script in quel modo, se sei abbastanza pazzo. Ad ogni modo, se vuoi estendere un alias, assicurati che l'alias che vuoi estendere finisca in uno spazio e fissane un altro.

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

7
Questo è orribilmente bello.
user1717828

Wow, è fantastico. Non lo sapevo (e probabilmente non lo useremo molto, perché penso che vada contro la Regola di Chiarezza ) ma è bello saperlo! Domanda, però: perché lo spazio all'inizio exdir? (È solo per allineamento per motivi estetici?)
Wildcard

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 "$@". Farlo con aliasesconsente di utilizzare le espansioni dei motivi in ​​modo più diretto e più sicuro. È necessario un secondo contesto evalquando viene chiamato dall'interno di una funzione, ma non è intrinsecamente pericoloso finché i nomi patterne listsono controllati da te. Possono rompersi solo nella maggior parte dei casi anche quando non lo sono, a meno che qualche attaccante non finisca consapevolmente correttamente case.
Mikeserv,

1
Io uso questo modello nel mio .bashrc: alias sudo='sudo 'questo mi permette di chiamare tutti i miei comandi alias dopo una sudo. Senza lo spazio non funzionerebbe
arainone il

1
@Wildcard - Non stavo esattamente sostenendo un simile uso, ma è vero che puoi, ed è anche vero che dovresti essere almeno un po 'matto per provare.
Mikeserv,

2

Una funzione è un'opzione migliore di un alias estendibile qui.

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

In questo modo, hai due opzioni per aggiungere opzioni all'ambiente:

  • Modifica l' grep_optionsarray; questo supporta correttamente le opzioni con spazi, caratteri letterali glob e altri casi d'angolo:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
  • Usa la GREP_OPTIONSvariabile scalare tradizionale , nonostante le sue insidie ​​(vedi BashFAQ # 50 per capirne alcune):

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

Detto questo, se si desidera che le opzioni vengano riflesse da grepistanze invocate all'esterno della shell, né un alias né una funzione lo faranno. Invece, vorrai uno script wrapper posizionato prima nel tuo PATH rispetto al grepcomando reale . Per esempio:

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

... e, in ~/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} "$@"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.