如何扩展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函数呢?
雅库耶

2
我完全同意-使用函数比使用别名更好。
查尔斯·达菲

Answers:


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'1

哇,太棒了 不知道这一点(可能不会使用太多,因为我认为这违背了清晰规则),但是很高兴知道!但是,问题是:为什么开头是空格exdir?(这仅仅是出于审美上的原因吗?)
通配符

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从函数内部调用时,确实需要第二个上下文w / ,但是只要pattern和的list名称由您控制,它并不是天生不安全的。除非某些攻击者故意正确地结束了您的攻击,但它们只能在大多数情况下才能破坏case
mikeserv '16

1
我在::中使用此模式,这使我可以在。之后调用所有别名命令。如果没有空间,这是行不通的.bashrcalias sudo='sudo 'sudo
arainone

1
@Wildcard-我并不是完全提倡使用这种方法,但确实可以,而且也必须至少有些疯狂才能尝试。
mikeserv '16

2

与此处的可扩展别名相比,函数是更好的选择。

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

这样,您就有两个选项可以向环境中添加选项:

  • 修改grep_options数组;这正确支持带空格,文字Glob字符和其他特殊情况的选项:

    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} "$@"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.