以编程方式解除引用/解析bash中的别名

时间:2013-01-06 09:40:04

标签: shell scripting bash

我需要以编程方式确定shell别名在bash中解析为哪个命令;即,我需要编写一个bash函数,该函数将使用一个可能引用别名的名称,并返回它最终引用的“真实”命令,在适用的情况下通过别名链递归。

例如,给定以下别名:

alias dir='list -l'
alias list='ls'

我的函数是dereference_alias

dereference_alias list    # returns "ls"
dereference_alias dir     # also returns "ls"

是否有一些内置我不知道这样做是否整齐,或者我是否应该自己去抓取alias的输出?

2 个答案:

答案 0 :(得分:2)

这是我编写的一个版本,它不依赖于任何外部命令,也可以在不创建无限循环的情况下处理递归别名:

# Arguments:
#
#   $1  Command to compact using aliases
#
function command-to-alias()
{
    local alias_key
    local expansion
    local guess

    local command="$1"
    local search_again="x"
    local shortest_guess="$command"

    while [[ "${search_again:-}" ]]; do
        unset search_again
        for alias_key in "${!BASH_ALIASES[@]}"; do
            expansion="${BASH_ALIASES[$alias_key]}"
            guess="${command/#"$expansion"/$alias_key}"
            test "${#guess}" -lt "${#shortest_guess}" || continue
            shortest_guess="$guess"
            search_again="x"
        done
        command="$shortest_guess"
    done

    echo "$command"
}

答案 1 :(得分:1)

以下是我的做法,虽然我不确定这是最好的方式:

dereference_alias () {
  # recursively expand alias, dropping arguments
  # output == input if no alias matches
  local p
  local a="$1"
  if [[ "alias" -eq $(type -t $a) ]] && p=$(alias "$a" 2>&-); then
    dereference_alias $(sed -re "s/alias "$a"='(\S+).*'$/\1/" <<< "$p")
  else
    echo $a
  fi
}

这里的主要缺点是我依赖于sed,并且我在别名中删除任何参数的方法在第一个空格处停止,期望任何别名都不会指向某个程序,由于某种原因,名称中有空格(即alias badprogram='A\ Very\ Bad\ Program --some-argument'),这是一个合理的足够的假设,但仍然如此。我认为至少整个sed部分可能会被利用bash自己的命令行解析/拆分/标记化的东西取代,但我不知道从哪里开始。