如何通过别名扩展通过管道输入 zsh?

如何通过别名扩展通过管道输入 zsh?

我试图通过将历史记录中的一行输入到 zsh 来运行:

cat ~/.zsh_history | cut -d ';' -f 2 | sk --tac | zsh

如果我交互选择的行sk是 中可用的命令PATH,例如man zsh.

但如果它是带有别名的东西,比如ck,而不是运行扩展cd .. && ls,我会收到“命令未找到”错误。


编辑:另外,如果我输入:

echo "cd .. && ls" | zsh

它打印在父目录中运行的输出ls,但是当命令退出时,我回到子目录中的原始提示符。有没有办法让 zsh 将通过管道传输到其中的内容视为我在提示符中手动输入并按 Enter 键?

答案1

将代码通过管道输送到zsh在单独的进程中运行该代码。此进程没有您的交互式设置,例如别名和函数(它不读取.zshrc),并且没有 shell 变量和当前 shell 的其他状态。当其他进程退出时,该进程的状态(例如当前目录)就会丢失。

要在当前 shell 进程中执行代码,请将其作为参数(而不是输入)传递给eval内置函数。

eval "$(<~/.zsh_history cut -d ';' -f 2 | sk --tac)"

但对于选择历史条目的特定用例,还有另一种方法。这fc内置。以下命令fcedit_sk使用一个参数运行该函数,该参数是临时文件的名称。当调用该函数时,该文件包含所有历史条目(${${(kn)history}[1]}是最旧条目的索引,-1表示最新条目)。当函数返回时,zsh 执行文件包含的任何内容,就像您在提示符下输入的一样。

fc -e fcedit_sk ${${(kn)history}[1]} -1

创建一个调用文件内容并将其输出写回文件的fcedit_sk函数。sk我不知道sk,所以我不知道是否有比这更简单的方法:

fcedit_sk () {
  local output
  output=$(sk --tac <$1)
  if (($?)); then
    echo >|$1 # Cancelled
  else
    print -lr -- $output >|$1
  fi
}

相关内容