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

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

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

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

cd ...
ls ...
realpath ...

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

$ alias '...'='../..'
$ type ...
... is aliased to '../..'
$ cd ...
bash: cd: ...: No such file or directory

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

答案1

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

alias -g ...=../..

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

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

$ set -o autocd
$ alias ...=../.. ....=../../..
$ ...

将是一种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

然后输入...会立即在视觉上转换为../..,再次按下.会更改为../../..等等。如果在emacs模式下,..后跟Alt+ 4,使用通常的方式.进行../../../../..举例(/..附加 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

正如 @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'

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

答案2

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

$ pwd
/home/terdon/foo/bar
$ v="../.."
$ realpath "$v"
/home/terdon

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

v="../.."

答案3

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

方法一:修改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

第2步:获取并应用补丁bash_5.16_cd_two_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

步骤 3:编译并运行

./configure
make
./bash

cd ... bash

方法2:在shopt中启用autocd

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

shopt -s autocd

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

方法 3:使用巧妙的别名

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

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

alias cd=cd_mod

cd_mod cd

答案4

您不能直接使用 alias ,因为...是 的参数cd,但我看到有些人别名cd..cd ..,所以您可以对所有命令执行类似的操作:

alias cd...='cd ../..'

另一方面...

$ cat ~/mycd 
if [ "$1" = '...' ]
then
  # Use \cd to prevent recursion
  \cd ../..
else
  \cd "$1"
fi

进而

alias cd=". ~/mycd"

或者,

mycd() { if [ "$1" = '...' ]; then \cd ../..; else \cd "$1"; fi; }
alias cd="mycd"

相关内容