5

我的bash(4.1)目录堆栈通常有十几个或更多条目。我想用dirswith替换输出dirs -v,所以我再也不用玩“猜魔数”pushd了。

我的部分解决方案

我替换为使用dirs执行的函数:dirs -vcommand

dirs()
{
    # "command" builtin prevents infinite recusion by suppressing lookup
    # of function and alias names.
    command dirs -v "${@}"
}

(更新:根据气动的建议,我现在使用builtin代替command。它不能解决这个问题,但它稍微安全一些。)

dirs输出现在可读,但pushd仍然popd产生旧的 vomit-of-slashes

$ pushd ~/just/one/more/and/ill/quit/i/promise
~/just/one/more/and/ill/quit/i/promise ~/tmp/bash/bash-4.1...
may/give/rise/to/dom /oh/no/not/again /var/adm/log /omg/wt...
va/lang ~/doc/comp/java/api/java/util/regex barf barf barf...

dirs用别名替换我的函数后,我得到了相同的(缺少)结果:

alias dirs='command dirs -v "${@}"'

解决方法

pushd我最终通过覆盖和得到了我想要的输出popd

pushd()
{
    command pushd "${@}" >/dev/null &&
      dirs
}
# popd is similar.

这可行,但它需要覆盖三个内置函数而不是一个。此外,这可能是一个不完美的模仿,pushd并且popd在某些极端情况下我没有想到。我宁愿dirs只覆盖。

我的问题

为什么覆盖dirs不起作用? 根据bashman页面,在pushd和下popd

如果pushd命令成功,dirs也会执行 a。

那么为什么pushd并且popd似乎调用了内置dirs函数而不是函数或别名呢?

关于bash文档的脚注

在线手册dirs中缺少“a is perform as well”的段落,但它们出现在页面和中。我的4.1 文档和当前的 4.4 文档都以相同的方式不一致,这表明 4.4(如果我有的话)的行为相同。bashref.*manbash.*builtins.*bash

4

2 回答 2

4

您想使用builtin而不是command. 我认为这就是您所追求的,覆盖到pushdand popd,同时保持dirs原样。

pushd(){ builtin pushd "$@" >/dev/null && dirs -v; }
popd() { builtin popd "$@" >/dev/null  && dirs -v; }
于 2016-09-27T04:04:12.530 回答
4

根据我对bash 源代码的阅读,两者都pushd调用popd内置dirs函数本身(没有任何参数),而不是咨询定义的别名和函数。

虽然内置函数利用外部功能似乎很少见,但当内置函数确实需要外部功能时,调用另一个内置函数似乎是先例。例如,当pushd更改目录时,它会调用cd内置的. 或者当declare需要类型转换一个变量时,它会调用setbuiltin

如何解决这个问题?pushd好吧,可以从源代码重新编译 bash:拥有并popd传递-v参数是微不足道的。还可以请求 bash 上游添加一个环境变量,该环境变量dirs在用作pushd/的帮助程序时定义了默认选项popd。但似乎最快的用户空间解决方案就像您所做的那样:只需覆盖所有三个。

于 2016-09-27T13:22:25.893 回答