总是在另一个命令之后运行一个命令

总是在另一个命令之后运行一个命令

使用zsh(和oh-my-zsh),是否可以始终在某个其他命令之后运行某个命令?我希望始终在进入目录ls后运行某个命令cd,而不是cd example; ls每次都运行。

我努力了:

function cd {
  cd $1
  ls
}

但它似乎zsh在运行时退出,没有任何输出(堆栈溢出?)。更改函数名称使其按预期工作,但我宁愿仍然使用该cd命令。

alias cd='cd $1;ls'

列出指定的目录,但实际上并不改变工作目录。

可以这样做吗?如果可以,怎么做?

答案1

尽管您自己已经解决了您的问题,但我还是想详细说明一下。

为什么你的别名不起作用:

@evilsoup 已经暗示了这一点,但要明确说明:别名(在狂欢)不能接受参数(而在韓軟體他们可以)。 将其视为一个简单的字符串替换。 因此,使用alias cd='cd $1;ls'defined,命令cd foo扩展为,cd ; ls foo因为$1是空的(在此上下文中不是定义),并且您会看到的内容,foo/但 shell 不会cd进入当前的目录(后面没有参数cd)。

为什么问题中的功能不起作用:

你定义了一个函数cd,它本身调用cd。因此你最终陷入了无限循环。当前的 zsh 版本 (5.0.2) 不会出现段错误,但会出现错误:

cd:1: maximum nested function level reached

builtin cd解决方案是在您的函数内部使用cd——正如您自己已经解决的那样。

为什么你的功能(来自那里)可以改进

您正在重新定义该cd函数。如果您明确调用它,效果很好。但 zsh 提供了AUTO_CD选项(使用 进行设置setopt AUTO_CD):

如果发出的命令不能作为普通命令执行,并且该命令是目录名称,则执行 cd 命令到该目录。

/var这意味着您只需输入/var而不是即可更改为cd /var。在这种情况下,您的cd函数不会被调用,并且您不会自动看到 的内容/var

pushdpopd还有一些情况,重新定义的cd命令没有帮助。

ZSH 方式

Stephane Chazelas 在 SE/UL 上已经给出了 zsh-ish 的方式,正如 @evilsoup 在评论中指出的那样:不要重新定义cd,而是使用钩子函数chpwd(),它的存在正是出于这个原因:

chpwd 每当当前工作目录改变时执行。

因此只需添加

function chpwd() {
  ls
}

到你的~/.zshrc。 (其简短形式chpwd() ls如链接答案中所示。)

答案2

Unix/Linux 上的帖子为我解决了这个问题:

function cd {
  builtin cd "$@" && ls -F
}

它与 bash 有关,但在 zsh 中对我有用。

答案3

不要chpwd()直接定义函数。

在 ZSH 中,有一个钩子chpwd专门用于在目录改变后运行命令。

不要chpwd()直接定义函数。它将覆盖挂载在 上的其他函数chpwd典范方法是定义一个函数,并将其加入到hook中chpwd,使得该函数与hook中的其他函数共存chpwd

# Hook onto `chpwd` in the right way
# with the official util add-zsh-hook

# wrap command `ls` into a function
_ls_on_cwd_change() {
  command ls;
}

# load add-zsh-hook if it's not available yet
(( $+functions[add-zsh-hook] )) || autoload -Uz add-zsh-hook

# hook _ls_on_cwd_change onto `chpwd`
add-zsh-hook chpwd _ls_on_cwd_change

# Additional info
# list existing hook functions
add-zsh-hook -L
# or
add-zsh-hook -L chpwd

答案4

我知道这已经有 10 年了,但我认为我只需发布一个当前时间的答案,这样到达这里的人可能会受益:

最简单的方法通常是最好的方法。过于复杂的启动脚本会导致以下问题:实际上需要添加一些复杂的东西。为此,我会使用别名匿名函数

alias cd='() { builtin cd "$@"; ls; }'

如果你已经有了 ls 的别名,希望在上面的别名中使用,您只需稍微修改一下就可以避免这种情况:

alias cd='() { builtin cd "$@"; command ls; }'

这是一种简单的方法,如果您需要在任何时间点直接运行真正的 cd 命令,您只需使用:

builtin cd <args>

如上一个别名所示。由于您处于匿名函数中,因此您可以做得更花哨。您可以在参数中添加分隔符,如“==”,然后将它之前的所有内容发送到光盘以及之后的一切ls. 最简单的形式(但远非完善):

alias cd='() { eval builtin cd ${${(s/==/)*}[1]}; eval ls ${${(s/==/)*}[2]}; }

(/s//)此处使用扩展标志来拆分为$*2 个数组。我们$*在此处使用是因为它是数组的标量形式$@。然后使用来eval强制解释器按原样(重新)评估输入行,将命令拆分为输入时的样子。

优点是您可以选择为 ls 提供过滤器或搜索选项,同时仍然能够在单个命令行中将常规命令行传递给 cd。

免责声明:

缺点是,像这样的字符串==很特殊,除非你用引号括起来,否则 zsh 会尝试扩展它"=="。因此,你可能希望使用其他标记对(尽管它没有成对出现)。我在这里使用它只是为了举一个简单的例子。

另外,请注意,如果您使用通配符,则必须将其括在引号中。这是因为通配符发生在执行命令之前。例如,如果您在目录 /home/myhome 中,并且您执行了以下操作:

cd /tmp "==" tmp*

您将获得与执行以下操作相同的结果:

builtin cd /tmp
command ls /home/myhome/tmp*

相反,你必须这样做:

cd /tmp "==" "tmp*"

这样,在处理命令行时eval就会处理 glob 。ls

此外,还有其他更有效的方法来分隔数组,但我认为这个示例即使是初学 zsh 用户也应该能够理解,而不必记住整个 zsh 手册。最后一个例子只是一个例子,还有很多更好的方法可以做到这一点。

无论如何,这对于 necro 助手帖子来说可能有点过分。我只是碰巧看到它并认为它很奇怪,因为即使在那时 zsh 中也存在匿名函数。希望它能对某些人有所帮助,这就是我发布它的原因。

:3

相关内容