我试图通过将历史记录中的一行输入到 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
}