将 cd 别名为 Pushd - 这是个好主意吗?

将 cd 别名为 Pushd - 这是个好主意吗?

使用以下别名是个好主意吗:

cd() {
    pushd $1;
}

在bash中?

我认为这非常有用,因为我可以使用一系列popds 而不仅仅是cd -一次。

有没有可能出现问题的情况?

答案1

就我个人而言,我的 bashrc 中有这些并一直使用它们:

pushd()
{
  if [ $# -eq 0 ]; then
    DIR="${HOME}"
  else
    DIR="$1"
  fi

  builtin pushd "${DIR}" > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

pushd_builtin()
{
  builtin pushd > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

popd()
{
  builtin popd > /dev/null
  echo -n "DIRSTACK: "
  dirs
}

alias cd='pushd'
alias back='popd'
alias flip='pushd_builtin'

然后,您可以像浏览器一样在命令行上导航。cd更改目录。back转到您之前cd编辑的目录。并将flip在当前目录和上一个目录之间移动,而不将它们从目录堆栈中弹出。总的来说,效果很好。

我知道的唯一真正的问题是,它是一组我完全习惯的命令,但在其他任何人的机器上都不存在。因此,如果我必须使用别人的机器,可能会有点令人沮丧。如果您习惯直接使用pushdand popd,就不会有这个问题。虽然如果您只是别名cdput not popd,则不会遇到不存在的问题,但仍然会遇到在其他计算机上无法达到预期效果的back问题。cd

但是,我要指出的是,您的特定实现cd并不完全像cd正常cd本身会进入您的主目录一样工作,但您的却不会。我这里的版本没有这个问题。我的也附加DIRSTACK在打印输出的前面dirs,但这更多的是个人品味的问题。

因此,正如我所说,我一直使用这些别名,并且对它们没有任何问题。只是不得不使用另一台机器然后发现它们不在那里可能会有点令人沮丧(这不应该令人惊讶,但它们是您经常使用的东西之一,以至于您不会想到它们,所以让它们不像你习惯的那样工作仍然会令人惊讶)。

答案2

这不是问题的直接答案,但我爱上了 4DOS 中的目录历史记录窗口。以至于我为 Linux(和 Cygwin)编写了自己的版本。我从来没有抽出时间让它成为一个易于安装的实用程序,但如果您了解 Bash 提示符的方法,那么它就不应该是很难跑起来。你的问题启发我将其放入 Git 存储库并上传到 GitHub:目录历史

基本上,它是一个从所有 shell 收集目录更改的守护进程,以及一个显示历史记录并允许您选择要切换到的任何目录的 Cdk 程序(因此您不限于堆栈)。我发现它非常有用,并将其绑定到 Ctrl-PageUp,就像 4DOS 那样。 (我什至修补了 PuTTY,以便它将 Ctrl-PageUp 发送到 Bash。)

答案3

对我来说,pushd/popd/dirs 几乎很有帮助,但缺乏。因此,我围绕这些创建了一个名为“navd”的“包装器”,本质上是作为一组 20 个别名来实现的。 (其中一个实际上是一个函数。)代码如下,但首先是一个简短的解释。 (“navd”和在其他人的机器上工作的一个好处是:有一种“免安装”形式运行它:作为一个安装选项,您可以简单地在 bash 提示符处粘贴实现“navd”的命令,并且在该机器的 bash 会话期间,navd 将在文件系统中提供零足迹,但它是一个临时安装,将这些命令放在 .bashrc 中以进行“真正”安装。课程。)

特征:

navd <path>;   -- will make that path the current dir AND will add it to the stack
                         AS A BONUS: If a relative path is used, this command is added to history
                         with an absolute path instead. This improves navigation even when only
                         using history ... because very often relative-path commands in history
                         are useless if the command changes the current directory. (After all, you
                         would have to be in the directory the command was originally issued
                         from in order for such a command to work correctly.)
navd           -- shows the stack, with index numbers for convenience
navd0          -- makes the first entry on the stack (read left-to-right) **the current dir**
navd1          -- makes the second entry on the stack (read left-to-right) **the current dir**
.
.
.
navd9          -- makes the tenth entry on the stack (read left-to-right) **the current dir**
navd-1         -- makes the first entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**
.                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^
.
.
navd-9         -- makes the 9th entry on the stack WHEN READ RIGHT-to-LEFT(!) **the current dir**

十九个 navd<N> 命令中的任何一个旋转堆栈这样目录就成为当前目录现在显示在堆栈的前面。正 <N> 值查找从左侧开始计数的目录,索引从零开始。负 <N> 值查找从右侧开始计数的目录,索引从 -1 开始。 (这遵循在 Java 和其他语言中如何使用数组索引的约定。)

注意:任何“navd”命令都会显示“pushd”和“dirs”使用的相同堆栈 - 但显示它时不带 最左边的条目将显示“dirs”(因为该条目实际上并不在堆栈上 - 它是当前目录 与“dirs”最左边的条目如果输入 cd 命令则更改)。 (“cd <path>”命令不会影响 navd 的任何行为虽然它确实会影响行为Pushd/dirs/popd 的。另外......我喜欢用“cd -”来“返回”一次到我刚刚导航离开的目录,并且“cd -”也不影响 navd 的行为。)

奖励:可以有另外 19 个别名,它们不会旋转堆栈,而只是将 dir 更改为堆栈上指示的位置。

 nav0 ... nav9   and   nav-1  ... nav-9

第二个奖励:“navh”显示历史记录中的 navd <path> 命令,以便通过剪切粘贴轻松加载堆栈。 (每个条目仅列出一次,即使它多次出现在历史记录中,并且列表已排序。此外,条目可以放入 $HOME/.navhignore 文件中,以防止这些条目出现在 navh 列表中。)

 navh

三个关键行为:

  1. 如果清除堆栈并重复特定的“navd <path>”命令,该路径将进入堆栈。这就是我想要和期望的......但是 Pushd 不会这样做 - 它将当前正在导航的目录放在堆栈上 - 因此当你重复命令时,堆栈上的效果是可变的(感觉不可预测) 。

  2. “navd <path>”不会将相同的路径放入堆栈两次。

  3. “navd <path>”将自己放入命令历史记录中绝对路径即使相对的输入命令的路径。

对我来说,所描述的最后三个行为使得使用历史记录中的“navd <path>”命令比使用历史记录中的“pushd <path>”命令更有帮助。我真的重用历史去往不同的地方。当我这样做时,我不会“破坏”我的堆栈。

如果您可以并且想要充分利用它,您可以在使用 navd 和 Pushd/dirs/popd 之间切换。两者使用相同的堆栈;只是风格不同而已。例如,使用“popd”从“navd”堆栈中删除内容,或使用“dirs -c”清除navd堆栈。

将 Pushd/dirs/popd 视为“我如何回溯我的步骤?”。
将 navd 视为“我如何保留一组最喜欢的目录,并在它们之间轻松切换?”。

将以下内容粘贴到终端窗口中,您可以在该终端会话期间立即开始使用 navd。这就是此功能的全部代码。

# Add 1 function and many related aliases for something like "pushd", called "navd". http://unix.stackexchange.com/a/229161
# Think of pushd/dirs/popd as "how do I retrace my steps?".
# Think of navd as "how do I hold on to a set of favorite directories, and easily switch between them?".
# Pseudo-code to explain each part of the "navd" bash function just below:
#              If no arguments to the 'navd' command:
#                  If stack has entries, then print the stack one-line-per-dir with each line numbered.
#                  Else, if stack is empty, automatically run the equivalent of the navh command.
#              Else (there **are** arguments to the 'navd' command):
#                  If arg is '--help' or '/?' then show help.
#                  Else    (arg is assumed to be a path to a directory)
#                      Remember the directory we are starting at
#                      Change to dir given as argument (the "arg-dir"), and do a few chores:
#                      Do not use arg-dir literally ... instead, magically put the **absolute** path we arrived at into history.
#                      Set a flag if the arg-dir is already in the stack.
#                      If the flag is set then just show the stack (on one line), else ADD to stack, ROTATE to end-of-stack, and show the stack.
#                      Change to dir we started at and then back to the arg-dir. This allows "cd -" to go back to dir we started at.
#                  End-If
#              End-If
navd () {
    if [[ $1 == '' ]]; then                             #--no arguments to the 'navd' command
        if dirs +1 >/dev/null 2>&1; then                #------stack has entries
            dirs -p | perl -ne 'print (-1+$cn++); print "$_"' | grep -v "^-1";
        else                                            #------stack is empty
            echo "The navd stack is empty. Now running 'navh' in case that's helpful. navd --help works."
            if [[ ! -f $HOME/.navhignore ]]; then echo -n ''>>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"
        fi
    else                                                #--(there **are** arguments to the 'navd' command)
        if [[ $1 == '--help' || $1 == '/?' ]]; then     #------arg is '--help' or '/?'
            echo "The 'navd' functionality is nothing but one bash function and a set of aliases."
            echo "It offers a different style of handy directory navigation than pushd/popd."
            echo "It uses the same 'stack' as pushd. Look in the .bashrc file for details."
            echo "    (Think of pushd/dirs/popd as 'how do I retrace my steps?'."
            echo "     Think of navd as 'how do I remember a set of favorite directories,"
            echo "     and easily switch between them?'.)"
            echo "As of 10/2015, this link has more info: http://unix.stackexchange.com/a/229161"
            echo "Here is the set of navd-related aliases. None need any parameter:"
            alias | grep 'alias nav' | cut -d= -f1 | grep -v '-' | grep -v 'navh'
            alias | grep 'alias nav' | cut -d= -f1 | grep '-'
            echo "alias navh  # The 'navh' alias has nothing to display until a 'navd <path>' is run. Short for nav-history."
            echo "---- To get started, simpy type navd followed by your favorite path. ----"
            echo "---- navd with no param shows stack. nav0 navigates to first on stack. ----"
        else                                            #------(arg is assumed to be a path to a directory)
            mypwd="$PWD"
            cd "$1" >/dev/null;
            history -s `echo "$PWD" | perl -pe 's/$ENV{'HOME'}/~/;s/ /\\\\ /g;s/^/navd /'`
            myflag=`dirs -p | perl -pe 's/\n/:/' | perl -ne '@a=split(":");$pwd=shift(@a);$flag=0;foreach (@a) {if ($_ eq $pwd) {$flag=1}};print $flag'`
            if [[ $myflag == 1 ]]; then dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"; else pushd .>/dev/null; pushd +1>/dev/null; dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"; fi
            cd "$mypwd"; cd "`dirs -l -0`"
        fi
    fi
};
# Aliases for navigating and rotating the "pushd" stack in the style of "navd":
alias navd0='cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"' # "-l" is dash-L, and expands "~" to denote the home dir. Needed inside back-ticks.
alias navd1='cd "`dirs -l +1`";pushd -n +1;cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd2='myd=$PWD;cd "`dirs -l +1`";for i in {1..2};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd3='myd=$PWD;cd "`dirs -l +1`";for i in {1..3};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd4='myd=$PWD;cd "`dirs -l +1`";for i in {1..4};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd5='myd=$PWD;cd "`dirs -l +1`";for i in {1..5};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd6='myd=$PWD;cd "`dirs -l +1`";for i in {1..6};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd7='myd=$PWD;cd "`dirs -l +1`";for i in {1..7};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd8='myd=$PWD;cd "`dirs -l +1`";for i in {1..8};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd9='myd=$PWD;cd "`dirs -l +1`";for i in {1..9};do pushd -n +1>/dev/null;cd "`dirs -l +1`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-1='cd "`dirs -l -0`";pushd -n -0>/dev/null; dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-2='myd=$PWD;cd "`dirs -l -0`";pushd -n -0>/dev/null;cd "`dirs -l -0`";pushd -n -0>/dev/null;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-3='myd=$PWD;cd "`dirs -l -0`";for i in {1..3};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-4='myd=$PWD;cd "`dirs -l -0`";for i in {1..4};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-5='myd=$PWD;cd "`dirs -l -0`";for i in {1..5};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-6='myd=$PWD;cd "`dirs -l -0`";for i in {1..6};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-7='myd=$PWD;cd "`dirs -l -0`";for i in {1..7};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-8='myd=$PWD;cd "`dirs -l -0`";for i in {1..8};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias navd-9='myd=$PWD;cd "`dirs -l -0`";for i in {1..9};do pushd -n -0>/dev/null;cd "`dirs -l -0`";done;cd "$myd";cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
# BONUS commands (beyond the 20). Aliases for navigating but NOT rotating the "navd" stack:
#      Help in remembering: "navd<#>" does more since it both changes the PWD and rotates the stack, whereas "nav<#>" does less
#            (and has one letter less) since "nav<#>" only changes the PWD. Also "navd<#>" acts like the pushd-related command: dirs
#      There is no "nav" command (with no number) so that there will be no conflict if any program called "nav" is used.
alias nav0='cd "`dirs -l +1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav1='cd "`dirs -l +2`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav2='cd "`dirs -l +3`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav3='cd "`dirs -l +4`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav4='cd "`dirs -l +5`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav5='cd "`dirs -l +6`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav6='cd "`dirs -l +7`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav7='cd "`dirs -l +8`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav8='cd "`dirs -l +9`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav9='cd "`dirs -l +10`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-1='cd "`dirs -l -0`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-2='cd "`dirs -l -1`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-3='cd "`dirs -l -2`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-4='cd "`dirs -l -3`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-5='cd "`dirs -l -4`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-6='cd "`dirs -l -5`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-7='cd "`dirs -l -6`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-8='cd "`dirs -l -7`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
alias nav-9='cd "`dirs -l -8`";dirs -p | perl -ne "chomp;s/$/ /;print unless ++\$cn==1"'
# BONUS command (beyond the 20). Alias for showing 'history' of all navd commands that add to the stack.
#                Can be used in a new terminal session to quickly add recently used dirs to the navd stack.
alias navh='if [[ ! -f $HOME/.navhignore ]]; then echo -n ''>>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"'
# Note: When 'navd <relative-path>' is used, then by bash-magic the navd command puts 'navd <absolute-path>' into history,
#       instead. This allows the output of "navh" to be useful regardless of the directory that is current when it is run.
#
# BONUS commands (beyond the 20). An even shorter alias for navd. An even shorter alias for navh.
alias nd='navd'
alias nh='if [[ ! -f $HOME/.navhignore ]]; then echo -n "">>$HOME/.navhignore;fi;diff --new-line-format="" --unchanged-line-format="" <(history | perl -ne "if (m/^\s*\d+\s+navd [\"~.\/]/) {s/^\s*\d+\s+/  /;s/\/$//;print}" | sort -u) <(cat $HOME/.navhignore | sort -u);echo "cat $HOME/.navhignore # (Has "`grep -c . <(sort -u $HOME/.navhignore)`" unique lines.)"'

这些别名基于“bash”命令。特别注意保持“cd -”的正常行为。 (很多时候我使用“cd -”而不是使用 Pushd 或 navd - 因为“cd -”非常方便地返回到您所在的最后一个“位置”,或者仅在两个位置之间切换,并且它可以在任何地方使用,无需安装。)

当然,可以将这些命令放入 .bashrc 文件中,以便更永久地安装它们。

答案4

这是您可能喜欢的另一个解决方案。我在使用@cjm 的解决方案后写了这篇文章。它使用dialog命令从dirs的输出创建ncurses类型菜单。选择一个项目会将该目录带到堆栈顶部并通过 cd 进入该目录。与目录历史记录相比,这有一个好处,即为每个终端模拟器提供自己的目录历史记录缓冲区,并且安装起来更容易一些。

安装:将 cd 别名设置为 Pushd 后,安装对话框,然后将此函数放入 bashrc 中:

dirmenu(){
    dirIter=$(dialog --backtitle 'dirmenu' --clear --cancel-label "Exit" --menu "Please select:" 0 0 0 $(dirs) 3>&2 2>&1 1>&3)
    cmd="builtin cd ~$dirIter"
    eval $cmd
}

我更喜欢这个,而不是运行 dirs -v,然后运行另一个命令来 pop 或 cd 到我想要的目录。对话框菜单还可以通过其dialogrc 进行高度自定义。

所以回答你的问题,是的,我认为将别名 Pushd 到 cd 是一个好主意。如果您定期重新启动计算机(至少是为了进行更新),则不太可能出现缓冲区溢出问题。尽管我在编写脚本时会小心使用 cd ; while 循环中的 cd 可能会导致缓冲区溢出问题。我不确定是什么控制 dirs/pushd 缓冲区大小。

相关内容