Как расширить псевдонимы bash


11

Как создать псевдоним, который фактически расширяет другой псевдоним с тем же именем в Bash?

Почему:

Я имел обыкновение GREP_OPTIONSустанавливать .bashrcчто-то вроде этого:

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

У меня также был сценарий (скажем, setup-java.sh), который я бы назвал, прежде чем работать над некоторыми проектами Java. Он будет содержать строку:

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

Если бы я также использовал Sass, я бы назвал, setup-sass.shкоторый содержит строку:

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

Но GREP_OPTIONSбыл признан устаревшим и, по-видимому, стандартным решением является создание псевдонима или какого-либо сценария ...


А как насчет функций Bash?
Jakuje

2
Я вполне согласен - использование функции является гораздо лучшим вариантом, чем псевдоним.
Чарльз Даффи

Ответы:


13

Bash хранит значения псевдонимов в массиве с именем BASH_ALIASES :

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

С расширением параметра мы можем получить либо последний установленный псевдоним (если существует), либо значение по умолчанию:

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

Теперь просто сделайте это на setup-java.sh:

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

... и наконец setup-sass.sh:

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

Если три строки называются, мы получаем то, что хотим:

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

13

aliases цепь, если вы заканчиваете их пробелами.

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

hello, fine fellow

Вы можете написать целые сценарии таким образом, если вы достаточно сумасшедший. В любом случае, если вы хотите расширить псевдоним, просто убедитесь, что псевдоним, который вы хотите расширить, заканчивается пробелом и добавьте еще один.

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
Это ужасно красиво.
user1717828

Вау, это круто Я не знал этого (и, вероятно, не буду использовать это много, потому что я думаю, что это идет вразрез с правилом ясности ), но это приятно знать! Вопрос, однако: почему пространство в начале exdir? (Это только для выравнивания по эстетическим причинам?)
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 "$@". Выполнение этого с помощью aliasesпозволяет вам использовать расширения шаблонов более напрямую и более безопасно. Вам нужен второй контекст ж / evalпри вызове из функции, но это не по своей сути небезопасно, пока patternи listназвания контролируются вами. Они могут разорвать только в большинстве случаев , даже если они не , если какой - то злоумышленник сознательно правильно заканчивается СВОЙ case.
mikeserv

1
Я использую этот шаблон в моем .bashrc:, alias sudo='sudo 'это позволяет мне вызывать все мои команды с псевдонимами после a sudo. Без места это не сработало бы
Arainone

1
@Wildcard - я не совсем защищал такое использование, но это правда, что ты можешь, и это также правда, что тебе нужно быть по крайней мере немного сумасшедшим, чтобы попробовать.
mikeserv

2

Функция здесь лучше, чем расширяемый псевдоним.

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

Таким образом, у вас есть два варианта для добавления параметров в среду:

  • Изменить grep_optionsмассив; это правильно поддерживает параметры с пробелами, буквенными символами глобуса и другими угловыми случаями:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
  • Используйте традиционную GREP_OPTIONSскалярную переменную, несмотря на ее недостатки (см. BashFAQ # 50, чтобы понять некоторые из них):

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

Тем не менее, если вы хотите, чтобы ваши параметры отражались grepэкземплярами, вызванными вне оболочки, ни псевдоним, ни функция не подойдут. Вместо этого вам нужно, чтобы скрипт-обертка был помещен в ваш PATH раньше, чем настоящая grepкоманда. Например:

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

... и в ~/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} "$@"
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.