如何在 zsh 中动态声明一些别名?

le-*_*ude 3 zsh alias cd-command quoting

我想声明一些快捷命令来在我的各种编码项目之间切换,所以我想出了以下脚本。

projects=$(ls -d ~/Workspace/*/)
prefix="/Users/myuser/Workspace/"
for f in $projects
do
        temp=${f#$prefix}
        temp=${temp/%\//}
        c="alias $temp='cd $f'"
        echo $c
        eval $c
done
Run Code Online (Sandbox Code Playgroud)

我把它放在我的主文件夹中一个名为的文件.workspace-shotcuts.sh中,然后我chmod +X .workspace-shotcuts.sh它。当我运行它时,使用./.workspace-shotcuts.sh我得到

alias project1='cd /Users/myuser/Workspace/project1/'
alias project2='cd /Users/myuser/Workspace/project2/'
Run Code Online (Sandbox Code Playgroud)

在控制台中。但是别名没有声明(zsh: command not found: project1)。

同样在我的.zshrc文件末尾,我添加了/bin/sh .workspace-shotcuts.sh,它提供了相同的输出,但仍然没有别名。

任何人都可以告诉我我缺少什么?我想指出的是,我不是一个出色的 *nix 用户,因此您可能需要对我进行一些 ELI5 操作。

编辑:

有人建议我source改用,我已经这样做了,但这是我收到的错误消息:

(eval):2: permission denied: /Users/myuser/Workspace/project1/
(eval):3: permission denied: /Users/myuser/Workspace/project2/    
(eval):4: permission denied: /Users/myuser/Workspace/project3/
(eval):5: permission denied: /Users/myuser/Workspace/project4/
(eval):6: permission denied: /Users/myuser/Workspace/project5/
(eval):7: permission denied: /Users/myuser/Workspace/project6/
(eval):8: permission denied: /Users/myuser/Workspace/project7/
(eval):9: no such file or directory: /Users/myuser/Workspace/project1=cd /Users/myuser/Workspace/project1/\n/Users/myuser/Workspace/project2/\n/Users/myuser/Workspace/project3/\n/Users/myuser/Workspace/project4/\n/Users/myuser/Workspace/project5/\n/Users/myuser/Workspace/project6/\n/Users/myuser/Workspace/project7/
Run Code Online (Sandbox Code Playgroud)

怎么了?我需要给我的脚本一些特殊许可吗?

Gil*_*il' 6

您的问题之一是您在单独的 shell 进程中执行了代码片段,这对父 shell 没有影响。这与如何在 shell 脚本中“导出”环境变量中的问题相同. 您需要使用source内置函数(也可以在 name 下使用.)在同一个 shell 中执行脚本。

source ~/.workspace-shotcuts.sh
Run Code Online (Sandbox Code Playgroud)

另一个问题是您正在尝试解析ls. 不要那样做。在诸如 sh 和 bash 之类的 shell 中,您可以避免使用它,因为$projects在引号之外写入会在分隔文件名的换行符处拆分值。除了它实际上不起作用:例如,如果文件名包含空格,它们将被分成以空格分隔的部分。在 shell 脚本中,不要解析 的输出ls,而是使用通配符。这在 zsh 中相当简单。

projects=(~/Workspace/*/)
for f in $projects; do …
Run Code Online (Sandbox Code Playgroud)

你接下来要做的事情相当复杂。你不需要eval这里;使用它只会让你引用不幸。由于您使用的是 zsh,因此您可以使用history 修饰符 t来提取路径的最后一个组件,而无需使用字符串操作构造:$f:t. 如果文件名包含特殊字符,您应该保护它们,并且 zsh 再次使这变得容易,这要归功于参数扩展标志 q${(q)f}为您提供一个带引号的文件名,您可以在别名定义中使用它。

projects=(~/Workspace/*/)
for f in $projects
do
  alias $f:t="cd ${(q)f}"
done
Run Code Online (Sandbox Code Playgroud)

但实际上,您只是在重新发明cdpathplusauto_cd。刮掉所有这些并使用

setopt auto_cd
cdpath+=~/Workspace
Run Code Online (Sandbox Code Playgroud)

auto_cd选项允许您键入目录名称以更改它,而无需cd ?在其之前键入。这cdpath是一个目录前缀数组,cd foo如果foo当前目录中没有调用子目录,它会尝试。


如果 bash 用户看到此线程:别名方法将是

projects=(~/Workspace/*/)
for f in "${projects[@]}"; do
  f=${f%/}
  alias ${f##*/}="cd '${f//\'/\'\\\'\'}'"
done
Run Code Online (Sandbox Code Playgroud)

CDPATH方法将是

CDPATH=$CDPATH:$HOME/Workspace
shopt -s autocd
Run Code Online (Sandbox Code Playgroud)