Kompakte Bash-Eingabeaufforderung bei Verwendung eines Verzeichnisbaums / Dateinamens


16

In einem System mit Ubuntu 14.04 und habe bashich die PS1Variable mit folgendem Inhalt:

\u@\h:\w\$

so dass die Eingabeaufforderung als angezeigt wird

user@machinename:/home/mydirectory$

Manchmal hat das aktuelle Verzeichnis jedoch einen langen Namen, oder es befindet sich in Verzeichnissen mit langen Namen, so dass die Eingabeaufforderung wie folgt aussieht

user@machinename:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name$

Dies füllt die Zeile im Terminal und der Cursor springt zu einer anderen Zeile, was ärgerlich ist.

Ich möchte stattdessen etwas wie erhalten

user@machinename:/home/mydirectory1/...another_long_name$

Gibt es eine Möglichkeit, die PS1Variable so zu definieren, dass der Verzeichnisname "umbrochen" und "komprimiert" wird, um niemals eine bestimmte Anzahl von Zeichen zu überschreiten und eine kürzere Eingabeaufforderung zu erhalten?


1
Zum Glück erinnere ich mich, wo ich gelesen habe, wie man die Shell-Eingabeaufforderung anpasst : tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html Dank geht an Giles Orr, Autor von Bash Prompt HOWTO, und an die Leute, die dazu beigetragen haben.
Stemd

Siehe auch unix.stackexchange.com/a/216871/117549 (ksh-basierte, aber ähnliche Idee)
Jeff Schaller

Antworten:


16

Zunächst einmal können Sie einfach ändern möchten das \wmit \W. Auf diese Weise wird nur der Name des aktuellen Verzeichnisses und nicht der gesamte Pfad gedruckt:

terdon@oregano:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name $ PS1="\u@\h:\W \$ "
terdon@oregano:my_actual_directory_with_another_long_name $ 

Dies ist möglicherweise immer noch nicht ausreichend, wenn der Verzeichnisname selbst zu lang ist. In diesem Fall können Sie die PROMPT_COMMANDVariable dafür verwenden. Dies ist eine spezielle Bash-Variable, deren Wert als Befehl ausgeführt wird, bevor jede Eingabeaufforderung angezeigt wird. Wenn Sie dies auf eine Funktion setzen, die die gewünschte Eingabeaufforderung basierend auf der Länge des aktuellen Verzeichnispfads festlegt, können Sie den gewünschten Effekt erzielen. Fügen Sie zum Beispiel diese Zeilen hinzu zu ~/.bashrc:

get_PS1(){
        limit=${1:-20}
        if [[ "${#PWD}" -gt "$limit" ]]; then
                ## Take the first 5 characters of the path
                left="${PWD:0:5}"
                ## ${#PWD} is the length of $PWD. Get the last $limit
                ##  characters of $PWD.
                right="${PWD:$((${#PWD}-$limit)):${#PWD}}"
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] ${left}...${right} \$\[\033[00m\] "
        else
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] "
        fi


}
PROMPT_COMMAND=get_PS1

Der Effekt sieht folgendermaßen aus:

terdon@oregano ~ $ cd /home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name
terdon@oregano /home...th_another_long_name $ 

10

Das Hinzufügen einer Zeichenrückgabe ist meine Hauptlösung dafür

Meine Eingabeaufforderung (die auch andere Dinge enthält, die sie noch länger machen) sieht also so aus:

Bildbeschreibung hier eingeben

Sie werden feststellen, dass das $ als neue Zeile zurückgegeben wird

Das schaffe ich mit

HOST='\[\033[02;36m\]\h'; HOST=' '$HOST
TIME='\[\033[01;31m\]\t \[\033[01;32m\]'
LOCATION=' \[\033[01;34m\]`pwd | sed "s#\(/[^/]\{1,\}/[^/]\{1,\}/[^/]\{1,\}/\).*\(/[^/]\{1,\}/[^/]\{1,\}\)/\{0,1\}#\1_\2#g"`'
PS1=$TIME$USER$HOST$LOCATION'\n\$ '

Beachten Sie, dass, obwohl in einer separaten Zeile, super lange Verzeichnisbäume wie

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails verkürzt auf

/home/durrantm/Dropbox/_/code/ruby__rails

dh "top 3 directorys / _ / bottom two directorys", was mir normalerweise am Herzen liegt

Dadurch wird sichergestellt, dass die Zeile aufgrund der Verzeichnisbaumlänge nie zu lang wird. Wenn Sie immer den vollständigen Verzeichnisbaum haben möchten, passen Sie einfach LOCATION an, d. H

LOCATION=' \[\033[01;34m\]`pwd`'


1
Wo beinhaltet Ihre Eingabeaufforderung eigentlich das $ ? (Siehe das .)
G-Man sagt, dass Monica am

Fügte das \ $ am Ende hinzu, danke. es war, weil ich normalerweise auch meinen Git-Zweig zeige, aber das ist zu viel Detail für hier
Michael Durrant

1
Was? Keine Newline? Kein SGR0?
G-Man sagt, dass Monica am

Linefeed
Michael Durrant

3

Erstellt ~ / .bash_prompt:

maxlen=36
# set leftlen to zero for printing just the right part of the path
leftlen=19
shortened="..."
# Default PWD
nPWD=${PWD}
if [ ${#nPWD} -gt $maxlen ]; then
  offset=$(( ${#nPWD} - $maxlen + $leftlen ))
  nPWD="${nPWD:0:$leftlen}${shortened}${nPWD:$offset:$maxlen}"
else
  nPWD='\w'
fi
echo "\u@\h:$nPWD\$ "

In meinem ~ / .bash_profil hinzugefügt:

function prompt_command {
  export PS1=$(~/.bash_prompt)
}
export PROMPT_COMMAND=prompt_command

Ausgabe ist:

user@machinename:/home/mydirectory1/...another_long_name$

1

Keine Lösung, um lange Pfade zu verkürzen, sondern eine bequeme Möglichkeit, einen besseren Überblick zu erhalten, während alle Pfadinformationen sichtbar bleiben, besteht darin, vor dem letzten Zeichen eine neue Zeile einzufügen. Auf diese Weise beginnt der Cursor immer in der gleichen Spalte, auch wenn der Pfad lang genug ist, um ihn zu umbrechen, die Konsolenfenster jedoch so hoch sein sollten, dass die vorherigen Zeilen nicht zu schnell ausgeblendet werden. Ich habe die Farbcodes aus Gründen der Übersichtlichkeit entfernt:

murphy@seasonsend:~
$ echo $PS1
\u@\h:\w\n\$
murphy@seasonsend:~
$ 

1

Ich benutze dies, es wird um die Länge von in mehrere Zeilen und Einrückungen umgebrochen, user@hostso dass davon ausgegangen wird , dass der Strom PS1effektiv " \u@\h:\w$" ist. Der Pfad wird nicht gekürzt und an die aktuelle Terminalbreite angepasst. Es teilt nur den Pfad auf /, so dass es nicht elegant mit wirklich langen Verzeichnissen umgeht (aber es bewahrt Leerzeichen für Auswahl / Kopieren). Es stellt sicher, dass immer mindestens 20 Zeichen für die Eingabe verfügbar sind.

readonly _PS1="${PS1}" 2>/dev/null

function myprompt()
{
    local IFS
    local nn nb pbits xpwd="" ww=60 len=0 pp='\\w\$ '
    local indent uh="${LOGNAME}@${HOSTNAME//.*/}"

    test -n "$COLUMNS" && let ww=$COLUMNS-20  # may be unset at startup

    PS1="${_PS1}"
    if [ ${#PWD} -ge $ww ]; then
        printf -v indent "%${#uh}s%s" " " "> "  # indent strlen(user@host)

        IFS=/ pbits=( $PWD ); unset IFS
        nb=${#pbits[*]}
        for ((nn=1; nn<nb; nn++)) {
            if [ $(( $len + 1 + ${#pbits[$nn]} )) -gt $ww ]; then
                xpwd="${xpwd}/...\n${indent}..."
                len=0
            fi
            xpwd="${xpwd}/${pbits[$nn]}"
            let len=len+1+${#pbits[$nn]}
        }
        # add another newline+indent if the input space is too tight
        if (( ( ${#uh} + len ) > ww )); then
            printf -v xpwd "${xpwd}\n%${#uh}s" " " 
        fi 
        PS1="${PS1/$pp/$xpwd}$ "    
    fi
}
PROMPT_COMMAND=myprompt

Dies funktioniert, indem Sie die Magie \w(nur \w$für diese Übereinstimmungen ) herausnehmen PS1und durch ersetzen und sie $PWDdann als einfache Zeichenfolge einwickeln. Es wird PS1jedes Mal neu berechnet, wenn der ursprüngliche Wert in gespeichert _PS1wird. Dies bedeutet, dass auch "unsichtbare" Escape-Zeichen beibehalten werden. Meine vollständige ursprüngliche Eingabeaufforderungszeichenfolge für xtermund die fett gedruckte Eingabeaufforderung:

PS1="\[\033]0;\u@\h:\w\007\]\[$(tput bold)\]\u@\h\[$(tput sgr0)\]:\w$ "

Und das Endergebnis ist ein Terminal mit 80 Spalten:

mr@onomatopoeia:~$ cd /usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace
mr@onomatopoeia:/usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/...
               > .../Perf/Trace$ _

Dies funktioniert ab bash-3.2 so wie printf -v vares verwendet wird. Aufgrund der unterschiedlichen Komplexität ist eine Anpassung für andere Varianten von erforderlich PS1.

(Der Pfad in der xterm- Titelleiste wird weder umbrochen noch abgekürzt. Dies könnte geschehen, indem eine der anderen Antworten hier in die obige Funktion eingefügt wird.)


0

Alternativ kann ich in meinem .zshrc auf den ersten Buchstaben jedes Verzeichnisses abkürzen, wenn die Pixelbreite über einer bestimmten Breite liegt:

user@machinename:/home/mydirectory1/second_directory
user@machinename:/home/mydirectory1/second_directory/my_actual_directory

wird:

user@machinename:/h/mydirectory1/second_directory
user@machinename:/h/m/s/my_actual_directory

Hier ist die zsh-Funktion, um dies zu tun:

     # get the path
     t=`print -P "%m:%~"`;
     t=`echo $t | sed -r 's/([^:])[^:]*([0-9][0-9]):|([^:])[^:]*([^:]):/\1\2\3\4:/'`;
     oldlen=-1;

     # create 4 buckets of letters by their widths
     t1="${t//[^ijlIFT]}";
     t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
     t3="${t//[^ABEKPSVXYCDHNRUw]}";
     t4="${t//[^GoQMmW]}";

     # keep abbreviating parent directories in the path until under 456 pixels
     while (( ( ( ${#t1} * 150 ) + ( ${#t2} * 178 ) + ( ${#t3} * 190 ) + ( ${#t4} * 201 ) ) > 4560 && ${#t}!=oldlen)) {
       oldlen=${#t};
       t=`echo $t | sed 's/\/\(.\)[^\/][^\/]*\//\/\1\//'`;
       t1="${t//[^ijlIFT]}";
       t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
       t3="${t//[^ABEKPSVXYCDHNRUw]}";
       t4="${t//[^GoQMmW]}";
     };

     PS1=$t

Ich verwende dies tatsächlich, um den Titel des Terminals zu aktualisieren, so dass ich bei mehreren Registerkarten immer sehen kann, welches Register welches ist. Die vollständige .zshrc-Datei dafür finden Sie hier .

Dies ist sehr praktisch, da es den Kontext beibehält und es Ihnen in zsh ermöglicht, schnell ein Verzeichnis im gleichen Format zu vervollständigen. (zB Tippen cd /h/m/s/<tab>wird automatisch vervollständigt cd /home/mydirectory1/second_directory)


Wie trifft dies auf die Frage des OP zu, wie die PS1-Eingabeaufforderung zu definieren ist?
Anthon

Aus Gründen der Übersichtlichkeit wurde $ t zu PS1
Richard

0

Versuchen Sie es mit diesem Python-Skript . Es schneidet einzelne Abschnitte des Pfadnamens genau so ab, wie Sie es in Ihrer Frage wollten. Es wird auch die Unicode-Ellipse verwendet, die nur eine anstelle von drei Spalten einnimmt.

Beispielausgabe für Ihren Pfad (bei einem Limit von 30 Zeichen):

/home/mydir…/second…/my_actua

Es ist erwähnenswert, dass diese Lösung Unicode in Verzeichnisnamen mithilfe von korrekt verarbeitet wcswidth. ${#PWD}, die andere Antworten verwendet haben, werden die visuelle Breite eines Pfads, der UTF-8-Zeichen enthält, stark falsch einschätzen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.