Bash PWD缩短

21 linux bash

我正在寻找一个bash函数,它会缩短长路径名,以防止我的PS1变量过长.有点像:

/this/is/the/path/to/a/really/long/directory/i/would/like/shortened
Run Code Online (Sandbox Code Playgroud)

最终可能会:

/t../i../t../p../to/a/r../l../d../i/w../like/shortened
Run Code Online (Sandbox Code Playgroud)

采用路径和最多可接受的字符数来缩短的东西对我的.bashrc文件来说是完美的.

eph*_*ent 35

不会给出相同的结果,但我的~/.bashrc包含

_PS1 ()
{
    local PRE= NAME="$1" LENGTH="$2";
    [[ "$NAME" != "${NAME#$HOME/}" || -z "${NAME#$HOME}" ]] &&
        PRE+='~' NAME="${NAME#$HOME}" LENGTH=$[LENGTH-1];
    ((${#NAME}>$LENGTH)) && NAME="/...${NAME:$[${#NAME}-LENGTH+4]}";
    echo "$PRE$NAME"
}
PS1='\u@\h:$(_PS1 "$PWD" 20)\$ '
Run Code Online (Sandbox Code Playgroud)

它将显示的路径限制为最多20个字符.如果路径超过20个字符,它将显示为/...d/like/shortened~/.../like/shortened.


Eva*_*all 15

这是您可能喜欢的仅限bash的解决方案.这会将路径的每个部分缩短为仍然可以完成制表符的最短前缀,并使用*而不是..作为填充.

#!/bin/bash

begin="" # The unshortened beginning of the path.
shortbegin="" # The shortened beginning of the path.
current="" # The section of the path we're currently working on.
end="${2:-$(pwd)}/" # The unmodified rest of the path.
end="${end#/}" # Strip the first /
shortenedpath="$end" # The whole path, to check the length.
maxlength="${1:-0}"

shopt -q nullglob && NGV="-s" || NGV="-u" # Store the value for later.
shopt -s nullglob    # Without this, anything that doesn't exist in the filesystem turns into */*/*/...

while [[ "$end" ]] && (( ${#shortenedpath} > maxlength ))
do
  current="${end%%/*}" # everything before the first /
  end="${end#*/}"    # everything after the first /

  shortcur="$current"
  shortcurstar="$current" # No star if we don't shorten it.

  for ((i=${#current}-2; i>=0; i--))
  do
    subcurrent="${current:0:i}"
    matching=("$begin/$subcurrent"*) # Array of all files that start with $subcurrent. 
    (( ${#matching[*]} != 1 )) && break # Stop shortening if more than one file matches.
    shortcur="$subcurrent"
    shortcurstar="$subcurrent*"
  done

  begin="$begin/$current"
  shortbegin="$shortbegin/$shortcurstar"
  shortenedpath="$shortbegin/$end"
done

shortenedpath="${shortenedpath%/}" # strip trailing /
shortenedpath="${shortenedpath#/}" # strip leading /

echo "/$shortenedpath" # Make sure it starts with /

shopt "$NGV" nullglob # Reset nullglob in case this is being used as a function.
Run Code Online (Sandbox Code Playgroud)

给它作为第一个参数的长度,并将路径作为可选的第二个参数.如果没有给出第二个参数,它将使用当前工作目录.

这将尝试缩短到给定的长度.如果那是不可能的,它只是给出了它可以提供的最短路径.

从算法上讲,这可能很糟糕,但结果却非常快.(快速shell脚本的关键是避免使用子shell和外部命令,尤其是在内部循环中.)

按照设计,它只缩短2个或更多字符('hom*'和'home'一样多的字符).

这不完美.在某些情况下,它不会尽可能缩短,例如,如果有多个文件的文件名共享前缀(如果存在foobar1和foobar2,则不会缩短foobar3.)

  • 我喜欢显示tab-completable的唯一前缀的想法. (5认同)

Dmi*_*kov 11

仅供参考,\wBash 4+中有一个内置的"缩短器":

PROMPT_DIRTRIM=3
Run Code Online (Sandbox Code Playgroud)

会缩短/var/lib/whatever/foo/bar/baz.../foo/bar/baz.

  • 大; 只是为了澄清:需要bash v4 +(OS X 10.8,例如,附带bash 3.2.48). (2认同)

bob*_*aul 9

我对Evan Krall的代码做了一些改进.它现在检查您的路径是否在$ HOME中开始并用〜/而不是/ h*/u*/开始缩短的变化

#!/bin/bash

begin="" # The unshortened beginning of the path.
shortbegin="" # The shortened beginning of the path.
current="" # The section of the path we're currently working on.
end="${2:-$(pwd)}/" # The unmodified rest of the path.

if [[ "$end" =~ "$HOME" ]]; then
    INHOME=1
    end="${end#$HOME}" #strip /home/username from start of string
    begin="$HOME"      #start expansion from the right spot
else
    INHOME=0
fi

end="${end#/}" # Strip the first /
shortenedpath="$end" # The whole path, to check the length.
maxlength="${1:-0}"

shopt -q nullglob && NGV="-s" || NGV="-u" # Store the value for later.
shopt -s nullglob    # Without this, anything that doesn't exist in the filesystem turns into */*/*/...

while [[ "$end" ]] && (( ${#shortenedpath} > maxlength ))
do
  current="${end%%/*}" # everything before the first /
  end="${end#*/}"    # everything after the first /

  shortcur="$current"
  shortcurstar="$current" # No star if we don't shorten it.

  for ((i=${#current}-2; i>=0; i--)); do
    subcurrent="${current:0:i}"
    matching=("$begin/$subcurrent"*) # Array of all files that start with $subcurrent. 
    (( ${#matching[*]} != 1 )) && break # Stop shortening if more than one file matches.
    shortcur="$subcurrent"
    shortcurstar="$subcurrent*"
  done

  #advance
  begin="$begin/$current"
  shortbegin="$shortbegin/$shortcurstar"
  shortenedpath="$shortbegin/$end"
done

shortenedpath="${shortenedpath%/}" # strip trailing /
shortenedpath="${shortenedpath#/}" # strip leading /

if [ $INHOME -eq 1 ]; then
  echo "~/$shortenedpath" #make sure it starts with ~/
else
  echo "/$shortenedpath" # Make sure it starts with /
fi

shopt "$NGV" nullglob # Reset nullglob in case this is being used as a function.
Run Code Online (Sandbox Code Playgroud)

此外,这里有一些我放在.bashrc文件中的函数来缩小shell显示的路径.我不确定编辑这样的$ PWD是否完全安全,因为一些脚本可能依赖于有效的$ PWD字符串,但到目前为止我没有偶尔使用的问题.请注意,我将上述脚本保存为"shortdir"并将其放入我的PATH中.

function tinypwd(){
    PWD=`shortdir`
}

function hugepwd(){
    PWD=`pwd`
}
Run Code Online (Sandbox Code Playgroud)

编辑2010年10月19日

在bash中执行别名的正确方法是修改$PS1变量; 这是解析提示的方式.在大多数情况下(99%的情况下),当前路径在提示字符串中为"\ w".我们可以使用sed替换它shortdir,如下所示:

#NOTE: trailing space before the closing double-quote (") is a must!!
function tinypwd(){                                                             
    PS1="$(echo $PS1 | sed 's/\\w/\`shortdir\`/g') "
}                                                                               

function hugepwd(){                                                             
    PS1="$(echo $PS1 | sed 's/[`]shortdir[`]/\\w/g') "                            
} 
Run Code Online (Sandbox Code Playgroud)


Joh*_*ica 5

Python脚本怎么样?这将首先缩短最长的目录名称,一次缩短一个字符,直到达到其长度目标或无法获得更短的路径。它不会缩短路径中的最后一个目录。

(我开始用普通的shell脚本编写此代码,但是人,bash讨厌字符串操作。)

#!/usr/bin/env python
import sys

try:
    path   = sys.argv[1]
    length = int(sys.argv[2])
except:
    print >>sys.stderr, "Usage: $0 <path> <length>"
    sys.exit(1)

while len(path) > length:
    dirs = path.split("/");

    # Find the longest directory in the path.
    max_index  = -1
    max_length = 3

    for i in range(len(dirs) - 1):
        if len(dirs[i]) > max_length:
            max_index  = i
            max_length = len(dirs[i])

    # Shorten it by one character.    
    if max_index >= 0:
        dirs[max_index] = dirs[max_index][:max_length-3] + ".."
        path = "/".join(dirs)

    # Didn't find anything to shorten. This is as good as it gets.
    else:
        break

print path
Run Code Online (Sandbox Code Playgroud)

输出示例:

$ echo $DIR
/this/is/the/path/to/a/really/long/directory/i/would/like/shortened
$ ./shorten.py $DIR 70
/this/is/the/path/to/a/really/long/directory/i/would/like/shortened 
$ ./shorten.py $DIR 65
/this/is/the/path/to/a/really/long/direc../i/would/like/shortened
$ ./shorten.py $DIR 60
/this/is/the/path/to/a/re../long/di../i/would/like/shortened
$ ./shorten.py $DIR 55
/t../is/the/p../to/a/r../l../di../i/wo../like/shortened
$ ./shorten.py $DIR 50
/t../is/the/p../to/a/r../l../d../i/w../l../shortened
Run Code Online (Sandbox Code Playgroud)