2009-10-24 6 views
19

Szukam funkcji basha, która skróci nazwy długich ścieżek, aby utrzymać nadmiernie długą zmienną PS1. Coś wzdłuż linii:Skracanie Bash PWD

/this/is/the/path/to/a/really/long/directory/i/would/like/shortened 

może skończyć jako:

/t../i../t../p../to/a/r../l../d../i/w../like/shortened 

coś, że miała ścieżkę i maksymalną dopuszczalną liczbę znaków, aby skrócić do byłby idealny dla mojego pliku .bashrc.

+3

Osobiście mam zachęcam po prostu do dwóch najwyższych katalogów, więc powyższe byłoby "li" ke/skrócony'. Używam ZSH, więc nie wiem, jak to zrobić w bash. – pavpanchekha

+1

@pavpanchekha 'pwd | sed -e "s |. */\ (. * /. * \) | \ 1 |" ' – polypus74

+1

I do użytku w PS1, można: funkcja pwd_depth_limit_2 { jeśli [" $ PWD "=" $ HOME "] następnie echo -n" ~ " else pwd | sed -e "s |. */\ (. * /. * \) | \ 1 |" fi } – polypus74

Odpowiedz

4

Co ze skryptem w języku Python? Skraca to najdłuższe nazwy katalogów, po jednym znaku na raz, dopóki nie osiągnie celu długości lub nie będzie w stanie skrócić ścieżki. Nie skraca ostatniego katalogu na ścieżce.

(zacząłem pisać to w prostym skrypcie ale człowiek, bash śmierdzi na ciąg manipulacji.)

#!/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 

Przykâadowa:

$ 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 
+0

Właśnie napisałem skrypt Pythona, który jest bardzo podobny do tego. Mój robi trochę więcej rekurencji, jest nieco bardziej wydajny i zupełnie nie przestaje skracać, gdy zostanie osiągnięta żądana długość. Dlatego nie zamierzam zawracać sobie głowy publikowaniem, chyba że komuś zależy. : -/ – Benson

+0

Nice. Moją jedyną obawą jest koszt wykonania skryptu Pythona przy każdym wykonaniu powłoki. Spróbuję i dam ci znać. –

+0

Jeśli jest zbyt wolny, daj mi znać, w razie potrzeby można go przyspieszyć. –

14

Oto bash-jedynym rozwiązaniem, które może chcesz . Skraca to każdą część ścieżki w dół do najkrótszego prefiksu, który nadal może być zakończony tabulatorem i używa * zamiast wypełnienia jako wypełniacza.

#!/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. 

Podaj długość jako pierwszy argument, a ścieżkę jako opcjonalny drugi argument. Jeśli nie podano drugiego argumentu, używa on bieżącego katalogu roboczego.

Spróbuje to skrócić do podanej długości. Jeśli nie jest to możliwe, daje tylko najkrótszą możliwą ścieżkę.

Pod względem algorytmicznym jest to prawdopodobnie okropne, ale kończy się dość szybko. (Kluczem do szybkich skryptów jest unikanie podpowłok i poleceń zewnętrznych, zwłaszcza w wewnętrznych pętlach).

Z założenia skraca się tylko o 2 lub więcej znaków ("hom *" to tyle samo znaków co "dom") .

To nie jest idealne. Są sytuacje, w których nie skróci się tak bardzo, jak to tylko możliwe, na przykład, jeśli istnieje kilka plików, których nazwy plików mają prefiks (jeśli istnieją foobar1 i foobar2, foobar3 nie zostanie skrócony).

+4

Podoba mi się pomysł wyświetlenia unikatowego prefiksu, który można ująć w karty. –

1

Oto relacja stosunkowo prosta rozwiązanie perl. Jest to krótki numer na tyle, że można go osadzić bezpośrednio na PS1, a nie niż podczas wywoływania skryptu. Podaje wszystkie znaki skróconych nazw zamiast zastępowania "." „”

 

$ echo '/this/is/a/realy/long/path/id/like/shortened' | 
perl -F/ -ane 'print join("/", map { $i++ < @F - 2 ? 
substr $_,0,3 : $_ } @F)' 
/thi/is/a/rea/lon/pat/id/like/shortened 

Nie mam natychmiast widząc piękny sposób, aby zastąpić znaki z, ale tu jest brzydki sposób:

 

echo '/this/is/a/realy/long/path/id/like/shortened' | 
perl -F/ -ane 'print join("/", map { m/(.)(.*)/; 
$_ = $1 . "." x (length $2 > 2 ? 2 : length $2) if $i++ < @F - 2; $_ } @F)' 
/t../i./a/r../l../p../i./like/shortened 
+0

Dzięki za to. Pożyczyłem go, aby zasugerował odpowiedź na (prawie) to samo pytanie na Superużytkownika. http://superuser.com/questions/180257/bash-prompt-how-to-have-t-initials-of-directory-path – Telemachus

34

nie daje ten sam wynik, ale mój ~/.bashrc zawiera

_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='\[email protected]\h:$(_PS1 "$PWD" 20)\$ ' 

, która ogranicza wyświetlaną ścieżkę maksymalnie do 20 znaków. Jeśli ścieżka ma więcej niż 20 znaków, zostanie wyświetlona jako /...d/like/shortened lub ~/.../like/shortened.

+1

To jest świetne. Prosty i skuteczny. –

+1

To jest oczywiście poprawna odpowiedź. Dzięki! – nibot

9

Wprowadziłem kilka poprawek do kodu Evan Krall. Teraz sprawdza, czy ścieżka rozpoczyna się w katalogu $ HOME i rozpoczyna skróconej odmiany z ~/zamiast/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. 

oto niektóre funkcje I umieścić w moim pliku .bashrc do zmniejszyć ścieżkę wyświetlaną przez powłokę. Nie jestem pewien, czy edycja pliku $ PWD jest całkowicie bezpieczna, ponieważ niektóre skrypty mogą być zależne od poprawnego łańcucha $ PWD, ale jak dotąd nie miałem problemów z okazjonalnym użyciem. Zauważ, że zapisałem powyższy skrypt jako "shortdir" i umieściłem go w mojej zmiennej PATH.

function tinypwd(){ 
    PWD=`shortdir` 
} 

function hugepwd(){ 
    PWD=`pwd` 
} 

EDIT 19 Paź 2010

Właściwym sposobem zrobić aliasy w bash jest poprzez modyfikację zmiennej $PS1; w ten sposób analizowany jest monit. W przypadkach NAJCZĘSTSZYCH (w 99% przypadków) bieżąca ścieżka jest w ciągu znaków zachęty jako "\ w". Możemy użyć sed do zastąpienia tego z shortdir, tak:

#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') "        
} 
11

FYI, jest wbudowany w \w "skracania" w bash 4+:

PROMPT_DIRTRIM=3 

skróci /var/lib/whatever/foo/bar/baz do .../foo/bar/baz.

+2

Świetne; aby wyjaśnić: wymaga bash v4 + (na przykład OS X 10.8 zawiera bash 3.2.48). – mklement0

+0

@mklement: poprawione, dziękuję –

1

Oto kolejny spin na odpowiedź Evana:

enter image description here

Ten wykorzystuje plusa (+) zamiast gwiazdką (*) dla skróconych ścieżek. Zastępuje ścieżkę HOME znakiem ~ i pozostawia niezmieniony końcowy segment katalogu. Jeśli końcowy segment ma więcej niż 20 znaków, skraca go do bitu, który można ująć w zakładkę i dodaje elipsy (...).

#!/bin/bash 
# Modified from http://stackoverflow.com/a/1617048/359287 
# By Alan Christopher Thomas (http://alanct.com) 

__pwd_ps1() 
{ 
    begin="" 
    homebegin="" 
    shortbegin="" 
    current="" 
    end="${2:-$(pwd)}/" # The unmodified rest of the path. 
    end="${end#/}" # Strip the first/
    shortenedpath="$end" 

    shopt -q nullglob && NGV="-s" || NGV="-u" 
    shopt -s nullglob 

    while [[ "$end" ]] 
    do 
     current="${end%%/*}" # Everything before the first/
     end="${end#*/}" # Everything after the first/

     shortcur="$current" 
     for ((i=${#current}-2; i>=0; i--)) 
     do 
     [[ ${#current} -le 20 ]] && [[ -z "$end" ]] && break 
     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 
     [[ -z "$end" ]] && shortcur="$subcurrent..." # Add character filler at the end of this string 
     [[ -n "$end" ]] && shortcur="$subcurrent+" # Add character filler at the end of this string 
     done 

     begin="$begin/$current" 
     homebegin="$homebegin/$current" 
     [[ "$homebegin" =~ ^"$HOME"(/|$) ]] && homebegin="~${homebegin#$HOME}" # Convert HOME to ~ 
     shortbegin="$shortbegin/$shortcur" 
     [[ "$homebegin" == "~" ]] && shortbegin="~" # Use ~ for home 
     shortenedpath="$shortbegin/$end" 
    done 

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

    [[ ! "$shortenedpath" =~ ^"~" ]] && printf "/$shortenedpath" # Make sure it starts with/
    [[ "$shortenedpath" =~ ^"~" ]] && printf "$shortenedpath" # Don't use/for home dir 

    shopt "$NGV" nullglob # Reset nullglob in case this is being used as a function. 
} 

Pobierz skrypt tutaj i umieścić go w swojej .bashrc:

https://raw.github.com/alanctkc/dotfiles/master/.bash_scripts/pwd-prompt.bash

. ~/.bash_scripts/pwd-prompt.bash 

Dodaj katalog do PS1 tak:

export PS1="[other stuff...] \$(__pwd_ps1)\$ " 
Powiązane problemy