在多个目录之间进行系统管理的快速命令行方法是什么?


46

在多个目录之间进行系统管理的快速命令行方法是什么?我的意思是,我可以使用pushd .popd进行切换,但是如果我想存储倍数并在它们之间循环,而不是将它们从堆栈底部永久弹出,该怎么办?


$CDPATH也许?
roaima

6
哦,我的-我是cd -从这个问题开始搜寻后才得知的。
纳赫特-恢复莫妮卡

@Nacht:您之前是如何浏览文件结构的?
loneboat '16

1
cd手工无处不在。很痛苦。但是,使用带有Tab键的自动完成功能。
Volomike '16

1
也许您想尝试一下。当您在同一对夫妇中跳跃很多时,非常方便。
罗尔夫(Rolf)

Answers:


28

使用pushd在目录栈,然后在目录中的特殊的名字:~1~2,等。

例:

tmp $ dirs -v
 0  /tmp
 1  /tmp/scripts
 2  /tmp/photos
 3  /tmp/music
 4  /tmp/pictures
tmp $ cd ~3
music $ dirs -v
 0  /tmp/music
 1  /tmp/scripts
 2  /tmp/photos
 3  /tmp/music
 4  /tmp/pictures
music $ cd ~2
photos $ cd ~4
pictures $ cd ~3
music $ cd ~1
scripts $ 

pushd以这种方式使用的最有效方法是加载目录列表,然后再添加一个目录作为当前目录,然后可以在静态编号之间跳转而不影响目录在堆栈中的位置。


另外值得一提的是,cd -将带你到你在最后一个目录。 所以会cd ~-

的优势,~-经过短短-的是,-特定于cd,而~-扩大你的shell以同样的方式~1~2等都是。在非常长的目录路径之间复制文件时,这非常方便。例如:

cd /very/long/path/to/some/directory/
cd /another/long/path/to/where/the/source/file/is/
cp myfile ~-

以上等同于:

cp /another/long/path/to/where/the/source/file/is/myfile /very/long/path/to/some/directory/

1
也可以使用cd -
Volomike '16

cd -就像Forth一样DROP DUP,例如,如果从目录a开始,堆栈为abcd,则a cd -将堆栈更改为bbcdbash但是,也许这是一个错误,因为一秒钟cd -将堆栈更改回abcd。由此可以推断,cd -除了更改堆栈之外,还使用一些单独的数据结构来存储先前的目录。
agc

3
@agc,cd -用途$OLDPWD,仅此而已。
通配符

所以也许cd -是较早的bash功能,后来又添加了一个堆栈,但是担心破坏旧代码比他们想要更简单的设计更多。对上一个的更正,其cd -行为类似于Forth OLDPWD @ SWAP OLDPWD ! DUP . Different cd foo,显示cd -已交换目录的名称。
AGC

或者总是有交互式推送包装器(该问题的其他答案包括自动跳转等)。
没用的2016年

42

bashpushd使用+和内置的-可以旋转目录堆栈。语法可能有些混乱,可能是因为该堆栈是从零开始的数组。这些简单的包装函数在目录堆栈中循环:

# cd to next     directory in stack (left  rotate)
ncd(){ pushd +1 > /dev/null ; }
# cd to previous directory in stack (right rotate)
pcd(){ pushd -0 > /dev/null ; }

测试:设置四个目录的堆栈。

dirs -c   # clear directory stack
cd /home ; pushd /etc ; pushd /bin ; pushd /tmp

现在/ tmp是当前目录,并且堆栈如下所示:

/tmp /bin /etc /home

切换到堆栈中的下一个目录(并显示),四次:

ncd ; pwd ; ncd ; pwd ; ncd ; pwd ; ncd ; pwd

输出:

/bin
/etc
/home
/tmp

切换到堆栈中的上一个目录(并显示它)四次:

pcd ; pwd ; pcd ; pwd ; pcd ; pwd ; pcd ; pwd

输出:

/home
/etc
/bin
/tmp

注释cd -通配符的答案有助于说明如何cd -不使用$ DIRSTACK数组(它使用$ OLDPW变量),因此cd -不会像基于堆栈的交换那样影响$ DIRSTACK。为了解决这个问题,这是一个基于$ DIRSTACK的简单交换函数:

scd() { { pushd ${DIRSTACK[1]} ; popd -n +2 ; } > /dev/null ; }

测试:

dirs -c; cd /tmp; \
pushd /bin; \
pushd /etc; \
pushd /lib; \
pushd /home; \
scd; dirs; scd; dirs

输出:

/bin /tmp
/etc /bin /tmp
/lib /etc /bin /tmp
/home /lib /etc /bin /tmp
/lib /home /etc /bin /tmp
/home /lib /etc /bin /tmp

我很沮丧的是,我想将物品放在堆栈中并保持在那里,直到选择清除堆栈为止。这样,我可以根据需要推,推,推,然后循环遍历三个方向。举例来说,我需要在三个目录之间切换,就像它们就像浏览器选项卡一样,然后来回移动,直到关闭选项卡。这是否以命令行方式解决?
Volomike '16

5
是的,我相信可以,请尝试一下。要删除顶部项目,请执行popd,在不更改目录的情况下将其删除,请执行popd -n。要清除堆栈呢dirs -c。不幸的是,bash设计人员将这种有用的功能隐藏在非直观的语法中。参见man bashpushddirs
AGC

作品!并且在文档中很清楚。现在,我知道这项技术,我喜欢它的简单性。
Volomike '16

13

我建议您安装fasd。通过键入名称的一小部分,它使您能够快速跳转到您已经进入的任何目录。

示例:如果您访问过/home/someName/scripts/,则只需输入z scr例如即可跳到那里。记住历史记录堆栈中的顺序或任何类似的方法,会更加方便。


10

当您在cd某个地方时,Bash将旧的工作目录存储在环境变量中$OLDPWD

您可以使用切换回该目录cd -,该目录等效于cd "$OLDPWD"

您可以像这样在目录之间来回跳动:

blue$ cd ~/green
green$ cd -
blue$ cd -
green$

6

我写了一个脚本xyzzy来做到这一点:

#!/bin/bash

i="$1"
i=$((${i//[^0-9]/}))
i="$(($i-1+0))"

b="$2"
b=$((${b//[^0-9]/}))
b="$(($b-1+0))"

if [ -z "$XYZZY_INDEX" ]; then
    XYZZY_INDEX="$((-1))"
fi

if [ ! -f "/tmp/xyzzy.list" ]; then
    touch /tmp/xyzzy.list
    chmod a+rw /tmp/xyzzy.list
fi
readarray -t MYLIST < /tmp/xyzzy.list

showHelp(){
read -r -d '' MYHELP <<'EOB'
xyzzy 1.0

A command for manipulating escape routes from grues. Otherwise known as a useful system admin
tool for storing current directories and cycling through them rapidly. You'll wonder why this
wasn't created many moons ago.

Usage: xyzzy [options]

help/-h/--help      Show the help.

this/-t/--this      Store the current directory in /tmp/xyzzy.list

begone/-b/--begone  Clear the /tmp/xyzzy.list file. However, succeed with a number and
            it clears just that item from the stored list.

show/-s/--show      Show the list of stored directories from /tmp/xyzzy.list

. #         Use a number to 'cd' to that directory item in the stored list. This syntax is odd:

            . xyzzy 2

            ...would change to the second directory in the list

. [no options]      Use the command alone and it cd cycles through the next item in the stored 
            list, repeating to the top when it gets to the bottom. The dot and space before xyzzy
            is required in order for the command to run in the current shell and not a subshell:

            . xyzzy

Note that you can avoid the odd dot syntax by adding this to your ~/.bashrc file:

  alias xyzzy=". xyzzy"

and then you can do "xyzzy" to cycle through directories, or "xyzzy {number}" to go to a
specific one.

May you never encounter another grue.

Copyright (c) 2016, Mike McKee <https://github.com/volomike>
EOB
    echo -e "$MYHELP\n"
}

storeThis(){
    echo -e "With a stroke of your wand, you magically created the new escape route: $PWD"
    echo "$PWD" >> /tmp/xyzzy.list
    chmod a+rw /tmp/xyzzy.list
}

begoneList(){
    if [[ "$b" == "-1" ]]; then
        echo "POOF! Your escape routes are gone. We bless your soul from the ever-present grues!"
        >/tmp/xyzzy.list
        chmod a+rw /tmp/xyzzy.list
    else
        echo -n "Waving your wand in the dark, you successfully manage to remove one of your escape routes: "
        echo "${MYLIST[${b}]}"
        >/tmp/xyzzy.list
        chmod a+rw /tmp/xyzzy.list
        for x in "${MYLIST[@]}"; do
            if [[ ! "$x" == "${MYLIST[${b}]}" ]]; then
                echo "$x" >> /tmp/xyzzy.list
            fi
        done
    fi
}

showList(){
    echo -e "These are your escape routes:\n"
    cat /tmp/xyzzy.list
}

cycleNext(){
    MAXLINES=${#MYLIST[@]}
    XYZZY_INDEX=$((XYZZY_INDEX+1))
    if [[ $XYZZY_INDEX > $(($MAXLINES - 1)) ]]; then
        XYZZY_INDEX=0
    fi
    MYLINE="${MYLIST[${XYZZY_INDEX}]}"
    cd "$MYLINE";
}

switchDir(){
    MYLINE="${MYLIST[${i}]}"
    cd "$MYLINE";
}

if [[ "$@" == "" ]];
then
    cycleNext
fi;

while [[ "$@" > 0 ]]; do case $1 in
    help) showHelp;;
    --help) showHelp;;
    -h) showHelp;;
    show) showList;;
    -s) showList;;
    --show) showList;;
    list) showList;;
    this) storeThis;;
    --this) storeThis;;
    -t) storeThis;;
    begone) begoneList;;
    --begone) begoneList;;
    *) switchDir;;
    esac; shift
done

export XYZZY_INDEX

我使用它的方式是先复制到/usr/bin文件夹,然后chmod a+x在其上。然后,我编辑我的root和用户帐户~/.bashrc文件以在底部包括以下几行:

alias xyzzy='. xyzzy'
alias xy='. xyzzy'

“ xy”是命令的缩写形式,可加快键入速度。

然后,我可以使用以下命令将当前目录存储在列表中:

xyzzy this

...并根据需要重复。当我用所需的目录填充此列表后,它们将保留在该目录中,直到我重新启动计算机为止,因为那是再次清除/ tmp的时候。然后我可以输入...

xyzzy show

...列出当前保存的目录。为了切换到目录,我有两种选择。一种选择是按索引指定路径(它是从1开始的索引),如下所示:

xyzzy 2

...将切换到列表中第二个目录。或者,我可以不使用索引号,而是这样做:

xyzzy

...让它根据需要遍历每个目录。要执行更多命令,请键入:

xyzzy help

当然,我添加的愚蠢的echo语句使工作更加有趣。

请注意,xyzzy是对Collosal Cave文字冒险的引用,在其中键入xyzzy可以让您在游戏中的两个房间之间切换,以避免产生毛刺。


2
+1我开始玩这个游戏。很好,但是如果还没有添加目录,而您仅输入xyzzy,似乎会失败。需要对cyclenext()中的MAXLINES -eq 0再进行一次测试。

5

我使用了一个名为z [link]的小脚本,即使它不能完全满足您的要求,也可能会引起您的兴趣。

NAME
       z - jump around

SYNOPSIS
       z [-chlrtx] [regex1 regex2 ... regexn]

AVAILABILITY
       bash, zsh

DESCRIPTION
       Tracks your most used directories, based on 'frecency'.

       After  a  short  learning  phase, z will take you to the most 'frecent'
       directory that matches ALL of the regexes given on the command line, in
       order.

       For example, z foo bar would match /foo/bar but not /bar/foo.

也许我错过了一些东西,但是我在哪里可以找到z脚本呢?

抱歉,链接在z上。将进行编辑以使其更易于查看。
Graipher

5

也有cd_funcPetar Marinov的书,基本上cd有多达10个条目的历史记录:http : //linuxgazette.net/109/misc/marinov/acd_func.html

# do ". acd_func.sh"
# acd_func 1.0.5, 10-nov-2004
# petar marinov, http:/geocities.com/h2428, this is public domain

cd_func ()
{
  local x2 the_new_dir adir index
  local -i cnt

  if [[ $1 ==  "--" ]]; then
    dirs -v
    return 0
  fi

  the_new_dir=$1
  [[ -z $1 ]] && the_new_dir=$HOME

  if [[ ${the_new_dir:0:1} == '-' ]]; then
    #
    # Extract dir N from dirs
    index=${the_new_dir:1}
    [[ -z $index ]] && index=1
    adir=$(dirs +$index)
    [[ -z $adir ]] && return 1
    the_new_dir=$adir
  fi

  #
  # '~' has to be substituted by ${HOME}
  [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}"

  #
  # Now change to the new dir and add to the top of the stack
  pushd "${the_new_dir}" > /dev/null
  [[ $? -ne 0 ]] && return 1
  the_new_dir=$(pwd)

  #
  # Trim down everything beyond 11th entry
  popd -n +11 2>/dev/null 1>/dev/null

  #
  # Remove any other occurence of this dir, skipping the top of the stack
  for ((cnt=1; cnt <= 10; cnt++)); do
    x2=$(dirs +${cnt} 2>/dev/null)
    [[ $? -ne 0 ]] && return 0
    [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}"
    if [[ "${x2}" == "${the_new_dir}" ]]; then
      popd -n +$cnt 2>/dev/null 1>/dev/null
      cnt=cnt-1
    fi
  done

  return 0
}

alias cd=cd_func

if [[ $BASH_VERSION > "2.05a" ]]; then
  # ctrl+w shows the menu
  bind -x "\"\C-w\":cd_func -- ;"
fi

Siimply使用cd --,以显示过去的清单给你10个目录cd艾德和cd -N(这里N是入门的指数)去那里。


4

我主要使用带有oh-my-zsh配置文件的ZSH 。您可以在终端中输入以下匹配项:

# cd /ho

然后,您可以简单地使用箭头(向上和向下)浏览所有shell历史记录,其中仅显示以上述字符开头的条目。因此,例如,如果您转到/home/morfik/Desktop//home/morfik/something/,则可以非常快速地在目录之间切换。在外壳程序历史记录中有多少个条目都没有关系,但是如果有很多条目,只需使用更好的表达式即可,例如cd /home/morf,在这里按键盘上的上/下箭头。

还有另一种方法可以实现该解决方案。在这种情况下,您必须使用tmuxFZF。然后,您只需要创建一个热键,例如ctrl-r,然后按它,您的当前窗口将被分割,您将看到以下内容:

在此处输入图片说明

现在,您可以使用表达式搜索列表。我刚刚输入^cd /media,它仅返回以短语开头的条目。当然,您可以键入'cd 'home以匹配命令以及整个目录名(而不是路径,仅是名称):

在此处输入图片说明


4

您可以在~/.bashrc(或同等的)别名中使用一堆别名来实现此目的。

主要目标是接近最小的键入(例如,d5跳转到池中的目录号5)以在池中的目录之间切换。另外,我们还想使向池中添加目录或从池中删除目录变得容易:

alias pd=pushd
alias po=popd
alias d='dirs -v'
alias d0=d
alias d1='pd +1'
alias d2='pd +2'
alias d3='pd +3'
alias d4='pd +4'
alias d5='pd +5'
alias d6='pd +6'
alias d7='pd +7'
alias d8='pd +8'
alias d9='pd +9'
alias d10='pd +10'
# -- feel free to add more aliases if your typical dir pool is larger than 10

现在,每次将目录压入堆栈时,目录都会添加到编号池0的位置(当前目录),您只需很少键入(d<N>)就可以跳转(切换目录),并且可以在任何位置查看编号的当前池只需输入时间即可d

使用这些别名的一些示例:

显示编号的目录池(当前目录为#0)

$ d
 0  /tmp
 1  /
 2  /usr

在目录之间切换:使用 d<N>

$ d2
$ pwd
/usr

将新目录添加到池中

$ pd /var/log
$ d
 0  /var/log
 1  /usr
 2  /tmp
 3  /

再跳一些:

$ d3
$ pwd
/

$ d3
$ pwd
/tmp

$ d
 0  /tmp
 1  /
 2  /var/log
 3  /usr

从池中删除/弹出顶部(当前)目录

$ po
$ d
 0  /
 1  /var/log
 2  /usr

2

如果安装了iselect,则可以执行以下操作:

$ alias dirselect='cd $(iselect -a $(dirs -l -p | sort -u))'
$ dirselect

这将为您提供基于ncurses的全屏交互式箭头键可导航菜单,以选择要访问的目录cd

如果您没有pushd在当前的shell会话中使用过,则菜单中的目录列表仅以一个条目(当前目录)开始。如果只有一个条目,则该dirselect别名将仅cd在没有菜单屏幕的情况下使用,因此它实际上不执行任何操作(除非阻止cd -执行任何有用的操作)

要将新目录添加到列表中,请使用pushd dir(或pushd -n dir在不添加cd-ing的情况下添加目录)

您可以pushd通过在.bashrc或中执行以下操作来预填充堆栈~/.bash_profile

for d in /var/tmp /tmp /path/to/somewhere/interesting ; do 
  pushd -n "$d" > /dev/null
done

您可以使用popd或删除条目popd -n

有关更多信息,请参见help pushdhelp popd以及help dirsbash中的。并且,当然man iselect

BTW,iselect可能已为您的发行版预先打包。它适用于Debian和Ubuntu等,也可能适用于其他人。



2

我正在使用Jump快速更改工作目录。

要添加当前目录:

jump -a [bookmark-name]

列出所有书签:

jump -l

例如:

------------------------------------------------------------------
 Bookmark    Path                                                 
------------------------------------------------------------------
 reports     ~/mydir/documents/reports
 projects    ~/documents/projects
 dl          ~/Downloads                     
------------------------------------------------------------------

现在,您可以轻松跳转到另一个目录:

jump reports

它支持bash和zsh的自动补全。


编辑(响应@Joe):二进制文件jump-bin存储在中/usr/local/bin,并使用bash集成脚本(位于我的PC上/var/lib/gems/1.9.1/gems/jump-0.4.1/bash_integration/shell_driver)创建一个bash函数jump,该函数调用jump-bin


跳转命令住在哪里?我没有它,也没有立即看到从哪里获得它。

2

我曾经alias导航。如果您很少访问频繁的目录,则只需设置别名即可。例如,

alias e='cd /etc'
alias h='cd /home'
alias al='cd /var/log/apache2/'

然后简单地

e 

会带你去/etc

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.