如何在 Bash 中将 `...` 别名为 `../..`?

Ani*_*nil 10 bash alias

如何在 Bash 中...使用别名../..

我知道其他答案允许,alias '...'='cd ../..'但我希望能够使用其他命令将目录寻址到两级,从而允许:

cd ...
ls ...
realpath ...
Run Code Online (Sandbox Code Playgroud)

我已经尝试过alias '...'='../..',但是当尝试使用它时,我得到以下信息:

$ alias '...'='../..'
$ type ...
... is aliased to '../..'
$ cd ...
bash: cd: ...: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我知道别名是用于命令的。在这种情况下,有没有办法为路径实现相同的功能?

Sté*_*las 26

如果可以选择切换到 zsh,您可以在那里使用全局别名:

alias -g ...=../..
Run Code Online (Sandbox Code Playgroud)

但无论如何,只有当...它本身被识别为完整的分隔标记时,它才会被扩展。echo ...它将在orecho ...> file或中展开(echo ...),但不会在echo .../xorecho ~/...echo "...") 中展开。

普通的 csh 样式别名,无论是在 bash 还是 zsh 中,仅在处于命令位置时或在另一个以空白字符结尾的别名扩展之后才会扩展。但是,在 zsh 中,如果您设置该autocd选项,则输入../..或另一个目录,因为命令名称会变成cd ../..,所以

$ set -o autocd
$ alias ...=../.. ....=../../..
$ ...
Run Code Online (Sandbox Code Playgroud)

将是一种cd进入的方式../..,但话又说回来,alias ...='cd ../..'或者...() cd ../..

我多年来一直使用的一种更好的方法是将键绑定.到插入的内容/..,而不是.光标左侧的内容是否以 结尾..

magic-dot() {
  if [[ $LBUFFER = (|*[[:blank:]/]).. ]]; then
    repeat ${NUMERIC-1} LBUFFER+=/..
  else
    zle self-insert
  fi
}
zle -N magic-dot
bindkey . magic-dot
Run Code Online (Sandbox Code Playgroud)

然后输入...会立即在视觉上转换为../..,再次按下.会更改为../../..等等。如果在emacs模式下,..后跟Alt+ 4,使用通常的NUMERIC.前缀处理进行../../../../..举例(附加 4 次) 。/..

过去,在复制/粘贴包含 的内容时,它有时会造成妨碍...,但现在引入了括号粘贴支持,这不再是问题。要输入文字,您可以在第三个字符之前...Ctrl+或使用反斜杠、引号或任何使光标左侧(上面)不会以, , ...结尾的内容。v.$LBUFFER<blanks-or-slash>...\....\.whatever/'...'

上述的一个有意的限制是,例如在 中sort -o......不被扩展。sort -o ...代替使用。cd '.../***'->也是如此cd ...'/***'。您可以更改上面的测试,[[ $LBUFFER = (|*[^.]).. ]]以便将其...扩展到../..更多上下文中,尽管这会增加它在您不希望的地方扩展的可能性。

我们可以通过允许向上4 级(扩展到)来使数字参数处理更加有用,例如:cd Alt+4.cd../../../..

magic-dot() {
  if (( NUMERIC )) && [[ $LBUFFER = (|*[[:blank:]/:]) ]]; then
    LBUFFER+=..
    (( NUMERIC-- ))
  fi
    
  if [[ $LBUFFER = (|*[[:blank:]/]).. ]]; then
    repeat ${NUMERIC-1} LBUFFER+=/..
  else
    zle self-insert
  fi
}
zle -N magic-dot
bindkey . magic-dot
Run Code Online (Sandbox Code Playgroud)

正如 @Gilles 在评论中提到的,最新版本的 bash 添加了对编辑绑定到键的命令中的行缓冲区的有限支持,因此您可以使用以下命令执行类似的操作:

insert_before_cursor() {
  # for the equivalent of zsh's repeat $1 LBUFFER+=$2
  local i
  for (( i = 0; i < $1; i++ )); do
    READLINE_LINE=${READLINE_LINE:0:READLINE_POINT}$2${READLINE_LINE:READLINE_POINT}
    (( READLINE_POINT += ${#2} ))
  done
}

magic-dot() {
  (( ${READLINE_ARGUMENT-1} > 0 )) || return
  if [[ -v READLINE_ARGUMENT && ${READLINE_LINE:0:READLINE_POINT} = ?(*[[:blank:]/]) ]]; then
    insert_before_cursor 1 ..
    (( READLINE_ARGUMENT-- ))
  fi

  if [[ ${READLINE_LINE:0:READLINE_POINT} = ?(*[[:blank:]/]).. ]]; then
    insert_before_cursor "${READLINE_ARGUMENT-1}" /..
  else
    insert_before_cursor "${READLINE_ARGUMENT-1}" .
  fi
}
bind -x '".":magic-dot'

# work around a bug in current versions of bash for the numeric
# argument to work properly, that means however that you lose the
# insert-last-argument normally bound to Meta-. (also on Meta-_)
bind -x '"\e.":magic-dot'
Run Code Online (Sandbox Code Playgroud)

您需要 bash 4.0 或更高版本$READLINE_LINE(不像$READLINE_LINE_BUFFER某些文档中拼写错误的那样),以及$READLINE_POINT,以及 5.2 或更高版本$READLINE_ARGUMENT,尽管如上所述,它目前还不能正常工作。


ter*_*don 12

您不能为此使用别名,别名是关于您执行的事情,而不是您作为参数传递给命令的事情。您可以使用变量,但这意味着键入稍有不同的内容。但如果您使用短变量名,则它可以只有两个字符:

$ pwd
/home/terdon/foo/bar
$ v="../.."
$ realpath "$v"
/home/terdon
Run Code Online (Sandbox Code Playgroud)

如果这对您有用,您可以将变量定义添加到您的~/.profile~/.bash_profile文件中,然后您就可以在 shell 会话中访问它:

v="../.."
Run Code Online (Sandbox Code Playgroud)


Sou*_*was 5

您可以通过多种方式实现目标

方法一:修改bash源码

此方法是特定于版本的,但仍然推荐,因为它是完成任务的好方法。我所做的修改builtins/cd.def是,在检查绝对路径之前,它会检查第一个参数是否为...if so,它将设置为dirname../..听起来只是别名)

第 1 步:下载bash-5.1.16.tar

wget http://ftp.gnu.org/gnu/bash/bash-5.1.16.tar.gz
Run Code Online (Sandbox Code Playgroud)

第 2 步:获取并应用补丁bash_5.16_cd_ Three_dot.patch

tar -xf bash-5.1.16.tar.gz
cd bash-5.1.16
wget https://gist.githubusercontent.com/s0ubhik/6685effe6e46f6a840bb480c5d657933/raw/5736ce64cbb0b009d872c21f40d69c8ee2942b74/bash_5.16_cd_three_dot.patch
patch -p0 < bash_5.16_cd_three_dot.patch
Run Code Online (Sandbox Code Playgroud)

第三步:编译并运行

./configure
make
./bash
Run Code Online (Sandbox Code Playgroud)

cd ... bash

方法2:在shopt中启用autocd

这种方法并不能完全满足您的要求,但我认为使用巧妙的别名技术更好

shopt -s autocd
Run Code Online (Sandbox Code Playgroud)

现在,如果您想返回一个目录,只需使用..and 表示两个目录../.. 自动光盘

方法 3:使用巧妙的别名

此方法有效,但不推荐,因为可能会对使用的各种脚本产生问题cd。您可以将其添加到您的文件中.bashrc或创建一个单独的文件,然后将该文件包含在.bashrc

cd_mod(){
  if [ "$1" == "..." ]; then
    \cd ../../
  else
    \cd $@
  fi
}

alias cd=cd_mod
Run Code Online (Sandbox Code Playgroud)

cd_mod cd

  • 可能不建议修改 Bash 源代码,除非您说服 Bash 上游合并更改。 (3认同)
  • 为什么叫“切刀别名”?还是“聪明”的拼写错误? (2认同)
  • 问题说“我希望能够使用其他命令**解决上两级目录的问题”,但您的建议都无法实现。现在,修补 Bash 源代码确实可以实现目标,但不能通过更改内置的 cd 来实现。它必须在全局参数处理中完成,例如“~”扩展到主目录。 (2认同)