如何在Bash中管理长路径?

时间:2009-03-22 03:02:55

标签: bash path

管理长路径时遇到问题。我怎样才能快速到达像

这样的路径
/Users/User/.../.../.../.../.../Dev/C/card.c

我尝试了别名

alias cd C='cd /Users/User/.../.../.../.../.../Dev/C'

但是我无法为两个单独的单词做别名。我在CDPATH中列出了很长的Bash别名和路径列表,所以我在犹豫是否要更多。如何管理长途径?

[回复的意见]

用户litb的回复揭示了我在管理中遇到的一些问题。诸如“CTRL + R”,“! - 3:1:2:4:x”和“增量搜索”之类的东西对我来说很难。它们可能有助于浏览长目录,从某种意义上讲,也可以帮助管理。

17 个答案:

答案 0 :(得分:32)

使用符号链接可能是最好的主意;但是你可以比将它们全部转储到你的主目录更容易。

正如你所提到的,BASH有一个名为 CDPATH 的功能,在这里非常方便。

只需在homedir中创建一个隐藏文件夹(这样就不会使你的homedir太乱了):

$ mkdir ~/.paths
$ cd ~/.paths
$ ln -s /my/very/long/path/name/to/my/project project
$ ln -s /some/other/very/long/path/to/my/backups backups
$ echo 'CDPATH=~/.paths' >> ~/.bashrc
$ source ~/.bashrc

这会在homedir中创建一个名为“.paths”的目录,其中包含您经常使用的所有长目录位置的符号链接,然后将CDPATH bash变量设置为该目录(在.bashrc中)并重新读取。 bashrc文件。

现在,您可以从任何位置转到任何路径:

$ cd project
$ cd backups

给你一个简短的CDPATH,没有混乱的别名,更重要的是:一个非常简单的方法导航到其他应用程序的那些长路径,例如UI应用程序,只需进入〜/ .paths或将该目录添加到UI应用程序的侧边栏中。

可能是您可以拥有的最简单的全方位解决方案。

答案 1 :(得分:24)

考虑使用符号链接。我有一个~/work/目录,我将符号链接放在我当前的所有项目中。

您也可以使用shell变量:

c='/Users/User/.../.../.../.../.../Dev/C'

然后:

cd "$c"

答案 2 :(得分:6)

在您的主目录(或您选择的其他地方)创建符号链接

ln -s longDirectoryPath~ / MySymLinkName

有关详细信息,请参阅man ln

答案 3 :(得分:5)

可能最简单的解决方案是使用:

alias cdc='cd /Users/User/.../.../.../.../.../Dev/C'
alias cdbin='cd /Users/User/.../.../.../.../.../Dev/bin'
alias cdtst='cd /Users/User/.../.../.../.../.../Dev/tst'

如果你一次只是在一个项目上工作。如果您处理多个项目,则可以使用另一个别名来更改上述别名中的目录。

所以,你会使用类似的东西:

proj game17
cdc
make
proj roman_numerals
cdbin
rm -f *
proj game17 ; cdc

由于这是一个有用的东西,我决定整理一系列可以使用的脚本。它们都基于您放置在主目录中的配置文件以及源脚本的别名。文件"~/.cdx_data"的格式为:

scrabble:top=~/dev/scrabble
scrabble:src=~/dev/scrabble/src
scrabble:bin=~/dev/scrabble/bin

sudoku:top=~/dev/scrabble
sudoku:src=~/dev/scrabble/src
sudoku:bin=~/dev/scrabble/bin
sudoku:data=~/dev/scrabble/data

并列出所有相关项目(本例中为scrabble和sodoku)及其目录(每个项目可能不同,但在此示例中有top,bin,src和data)。

第一个动作是初始化东西,所以把:

. ~/.cdx_init

在.bash_profile的末尾,并将"~/.cdx_init"文件创建为:

alias cdxl='. ~/.cdx_list'
alias projl='. ~/.cdx_projlist'
alias cdx='. ~/.cdx_goto'
alias proj='. ~/.cdx_proj'

这将设置四个别名以获取我将在下面包含的文件。用法是:

cdxl     - List all directories in current project.

projl    - List all projects.

proj     - Show current project.
proj <p> - Set current project to <p> (if allowed).

cdx      - Show current project/directory and expected/actual real
           directory, since they can get out of sync if you mix cd and cdx.
cdx .    - Set actual real directory to expected directory (in other words,
           get them back into sync).
cdx <d>  - Set directory to <d> (if allowed).

实际的脚本如下。首先,".cdx_list"只列出当前项目中允许的目录(管道分为多行以便于阅读,但它们都应该在一行上)。

echo "Possible directories are:"
cat ~/.cdx_data
    | grep "^${CDX_PROJ}:"
    | sed -e 's/^.*://' -e 's/=.*$//'
    | sort -u
    | sed 's/^/    /'

同样,".cdx_projlist"显示了所有可能的项目:

echo "Possible projects are:"
cat ~/.cdx_data
    | grep ':'
    | sed 's/:.*$//'
    | sort -u
    | sed 's/^/    /'

在内容丰富的脚本中,".cdx_proj"设置和/或显示当前项目:

if [[ "$1" != "" ]] ; then
    grep "^$1:" ~/.cdx_data >/dev/null 2>&1
    if [[ $? != 0 ]] ; then
        echo "No project name '$1'."
        projl
    else
        export CDX_PROJ="$1"
    fi
fi
echo "Current project is: [${CDX_PROJ}]"

".cdx_goto"对于项目中的目录是相同的:

if [[ "$1" == "." ]] ; then
    CDX_TMP="${CDX_DIR}"
else
    CDX_TMP="$1"
fi
if [[ "${CDX_TMP}" != "" ]] ; then
    grep "^${CDX_PROJ}:${CDX_TMP}=" ~/.cdx_data >/dev/null 2>&1
    if [[ $? != 0 ]] ; then
            echo "No directory name '${CDX_TMP}' for project '${CDX_PROJ}'."
            cdxl
    else
            export CDX_DIR="${CDX_TMP}"
            cd $(grep "^${CDX_PROJ}:${CDX_DIR}=" ~/.cdx_data
                | sed 's/^.*=//'
                | head -1
                | sed "s:^~:$HOME:")
    fi
fi
CDX_TMP=$(grep "^${CDX_PROJ}:${CDX_DIR}=" ~/.cdx_data
    | sed 's/^.*=//'
    | head -1
    | sed "s:^~:$HOME:")
echo "Current project   is: [${CDX_PROJ}]"
echo "Current directory is: [${CDX_DIR}]"
echo "                      [${CDX_TMP}]"
echo "Actual  directory is: [${PWD}]"
unset CDX_TMP

它使用三个保留供自己使用的环境变量:"CDX_PROJ""CDX_DIR""CDX_TMP"。除了那些以及上述文件和别名之外,没有使用其他资源。这是我能想出的最简单但最具适应性的解决方案。祝你好运。

答案 4 :(得分:4)

再谈。今天我从社交书签网站收到了这个链接,然后我立刻想起了这个问题:

<强> Navigation with bm

  

我们保留简单明了的文字书签   文件并使用一个名为bm的工具来做   查找。该工具也可以   用于编辑书签索引   动态如下图所示   添加上一个目录   示例到索引。

答案 5 :(得分:3)

在.bashrc中找到

PS1='${debian_chroot:+($debian_chroot)}[\033[01;32m]\u@\h[\033[00m]:[\033[01;34m]
 \W[\033[00m]\$ '
并用 \ W 替换 \ w 。我已经在这里更改了。这只会为您提供您工作的主目录。您可以通过键入pwd

来获取完整目录

答案 6 :(得分:3)

用户jhs建议使用Pushd和Popd命令。我在这里分享一些我在Unix Power Tools -book中找到的Bash脚本。当你的目录变得太长时,它们非常酷:)

#Moving fast between directories 
alias pd=pushd 
alias pd2='pushd +2'  
alias pd3='pushd +3' 
alias pd4='pushd +4'

命令'pushd + n'“旋转”堆栈。反向命令'popd + n'删除堆栈的n条目。如果你的堆栈太长,请使用'repeat n popd'。例如,您的堆栈长度为12个目录:

repeat 11 popd 

当你想看到你的堆栈时,写下'pushd'。如需进一步阅读,我推荐第625-626页的书。

答案 7 :(得分:3)

您可能需要考虑在.bashrc中使用this之类的脚本。自从我阅读那篇文章以来,我每天都在使用它。非常有用。

答案 8 :(得分:3)

一旦我进入这么长的目录,我就有了历史。然后我只需输入Ctrl-R作为“(反向搜索)”提示并键入几个字符,如Dev/C出现在路径中的某个位置,它会显示我发出的命令那时候,我可以很容易地再次跳到它。

这在实践中非常有效。因为如果你没有在很长一段时间内输入该路径,它将找不到一个条目,这意味着做一些工作以使事情变得更容易可能不值得花时间。但如果你最近使用它肯定会找到它。这正是我需要的。

在某种程度上,它是一个用于长命令的自组织缓存。路径名:)

答案 9 :(得分:2)

有一些基本的众所周知的想法,比如创建别名:

alias cdfoo="cd /long/path/to/foo"

还有“掉落鹅卵石”

export foo=/long/path/to/foo

并且还使上述“基于项目”。我使用“基于票证”的目录。

 topdir=ticket_12345
 alias cdfoo="cd home/me/sandbox/$topdir/long/path/to/foo"
 export foo="/home/me/sandbox/$topdir/long/path/to/foo"

但除此之外,有时使用命令行菜单来回跳转到最近的位置是很方便的。 (pushd和popd很麻烦,恕我直言)。

我使用acd_func.sh(如下所列)。一旦定义,你可以做

cd -

查看最近目录的列表,带有数字菜单

cd -2

转到第二个最新目录。

非常好用,非常方便。

以下是代码:

   # Insert into .profile, .bash_profile or wherever
    # 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

答案 10 :(得分:2)

这可能是放入.bashrc的有用功能;它会向上移动多个目录,或移动到命名目录,即如果您在/a/b/c/d/,则可以up 3up a结束a

我不知道我在哪里找到了这个;如果您知道,请评论或添加归属地。<​​/ p>

function up()
{
    dir=""
    if [ -z "$1" ]; then
        dir=..
    elif [[ $1 =~ ^[0-9]+$ ]]; then
        x=0
        while [ $x -lt ${1:-1} ]; do
            dir=${dir}../
            x=$(($x+1))
        done
    else
        dir=${PWD%/$1/*}/$1
    fi
    cd "$dir";
}

答案 11 :(得分:2)

如果你想切换到zsh,这很容易 - 只需使用“alias -g”(全局别名,即在命令中任何地方都可以使用的别名,而不仅仅是第一个单词)。

# alias -g c=/my/super/long/dir/name
# cd c
# pwd
/my/super/long/dir/name

在bash中,我认为你最接近“混叠”风格的是写一个函数:

function ccd {
  case "$1" in
    c) cd /blah/blah/blah/long/path/number/one ;;
    foo) cd /blah/blah/totally/different path ;;
    "multiword phrase") cd /tmp ;;
  esac
}

这意味着当你想要一个快捷方式时,使用“cd”以外的东西作为命令,但除此之外,它是灵活的;你还可以在函数中添加一个“ls”,这样它就可以在cd等之后提醒你目录中的内容。

(请注意,要使用上面的多字参数,您需要在命令行中引用它,如下所示:

ccd "multiword phrase"

所以这并不是那么方便。但是如果你需要,它会起作用。)

答案 12 :(得分:2)

根据Andrew Medico的建议,查看J

答案 13 :(得分:1)

结帐autojmpdirmarks

答案 14 :(得分:1)

管理需要快速创建和删除目录。创造许多直率:

mkdir -p user/new_dir/new/_dir/.../new_dir

递归删除许多目录(当你在较低目录时要非常小心!):

rm -r dir/.../new_dir/

为了进一步阅读,备忘单可以帮助您:

  

http://www.scribd.com/doc/2082838/Bash-Command-Line-History-Cheat-Sheet

它包含一些金块,但我发现它很难阅读。我无法获得像Meta +&gt;这样的命令。它们可能会帮助您浏览长目录。

答案 15 :(得分:1)

我意识到这个问题已经很老了,但那里的剧本都没有让我满意,所以我写了一个新的。

以下是我的要求:

1)仅使用bash命令 - 我打算在许多不同的unices上使用它 - Linux,cygwin,HP-UX,AIX和其他几个,所以我不能依赖grep是一致的。幸运的是,我到处工作都有打击。

2)短代码 - 我希望能够将它绑定到GNU屏幕中的一个键,然后点击该键将脚本粘贴到我正在使用的当前bash shell中,这样我就没有了在我使用的每个系统上设置bash配置文件。任何超长的东西都会令人烦恼并且花费太多时间来粘贴。

3)没有文件使用 - 不想乱丢随机文件的共享登录。

4)在正常情况下就像“cd”一样行动。在开始输入之前,不想考虑使用哪个命令。

5)像这个答案一样提供“up”用法:How to manage Long Paths in Bash?

6)保留最近使用的目录列表,并切换到最新目录。

这是脚本:

#Jump History - Isaiah Damron
function jfind() {
    lp=${JNHIST//==${PWD}==/==}
    lp=${lp%%${lp#==*$1*==}}
    lp=${lp##${lp%==*$1*==*}}
    lp=${lp//==/}
    [[ -d "$lp" ]] && echo $lp && return 0
    return 1;
}
function jadd() {
    [[ -z "$JNHIST" ]] && export JNHIST='=='
    [[ 3000 -lt ${#JNHIST} ]] && export JNHIST=${JNHIST:0:3000} && export JNHIST="${JNHIST%==*}=="
    export JNHIST="==$PWD${JNHIST//==${PWD}==/==}"
}
function j() {
    { cd $* 2> /dev/null && jadd; } \
    || { cd ${PWD/$1*/}$1 2> /dev/null && jadd; } \
    || { jfind $1 \
        && { cd $( jfind $1  ) 2> /dev/null && jadd; } ; } \
    || cd $*
}
function jh() {
    [[ -z "$1" ]] && echo -e ${JNHIST//==/\\n} 
    [[ -n "$1" ]] && jfind $1 && cd $(jfind $1) && jadd
}

用法:

jh [parameters]

如果单独调用,没有任何参数,则输出当前历史列表。如果它有一个参数,那么它会在历史记录中搜索最近使用的包含字符串$ 1的目录,并在其中搜索cd。

j {parameters}

cd parameters。如果失败,它会检查$ PWD的任何父目录是否与$ 1匹配,并且cd是否与之匹配。如果失败,则调用jh $1。如果失败,则输出cd parameters

的结果

注意:我使用'=='作为内部分隔符。希望你没有任何包含'=='的目录,但如果你这样做,你将不得不改变脚本。只是:%s / == / whatever / g

答案 16 :(得分:1)

查看pushd,它允许您维护一堆目录,您可以将其推入,弹出或重新排列。