Prompt bash compatto quando si utilizza un albero di directory / nome file


16

In un sistema con Ubuntu 14.04 e bash, ho la PS1variabile che termina con i seguenti contenuti:

\u@\h:\w\$

in modo che il prompt appaia come

user@machinename:/home/mydirectory$

A volte, tuttavia, la directory corrente ha un nome lungo o si trova all'interno di directory con nomi lunghi, in modo che il prompt assomigli

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

Questo riempirà la linea nel terminale e il cursore si sposterà su un'altra linea, il che è fastidioso.

Vorrei invece ottenere qualcosa di simile

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

C'è un modo per definire la PS1variabile per "avvolgere" e "compattare" il nome della directory, per non superare mai un certo numero di caratteri, ottenendo un prompt più breve?


1
Fortunatamente ricordo dove ho letto come personalizzare il prompt della shell: tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html Grazie a Giles Orr, autore di Bash Prompt HOWTO e alle persone che hanno contribuito ad esso.
Il

Vedi anche unix.stackexchange.com/a/216871/117549 (basato su ksh, ma un'idea simile)
Jeff Schaller

Risposte:


16

Prima di tutto, potresti semplicemente voler cambiare \wcon \W. In questo modo, viene stampato solo il nome della directory corrente e non l'intero percorso:

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 $ 

Ciò potrebbe non essere ancora sufficiente se il nome della directory stesso è troppo lungo. In tal caso, è possibile utilizzare la PROMPT_COMMANDvariabile per questo. Questa è una variabile bash speciale il cui valore viene eseguito come comando prima che venga mostrato ogni prompt. Quindi, se lo si imposta su una funzione che imposta il prompt desiderato in base alla lunghezza del percorso della directory corrente, è possibile ottenere l'effetto desiderato. Ad esempio, aggiungi queste righe al tuo ~/.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

L'effetto è simile al seguente:

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

L'aggiunta di un ritorno al personaggio è la mia soluzione principale a questo

Quindi il mio prompt (che ha anche altre cose, rendendolo ancora più lungo) è simile al seguente:

inserisci qui la descrizione dell'immagine

Noterai che $ viene restituito come nuova riga

Ci riesco con

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\$ '

Si noti che, anche se su una riga separata, alberi di directory super lunghi come

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails sono abbreviati in

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

vale a dire "prime 3 directory / _ / ultime due directory" che di solito è ciò che mi interessa

Questo farà in modo che la linea non si allunghi troppo a causa della lunghezza dell'albero delle directory. Se si desidera sempre l'albero della directory completo, regolare LOCATION, ad es

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

Maggiori informazioni sul colore su unix.stackexchange.com/q/124407/10043
Michael Durrant,

1
Dove viene effettivamente incluso il tuo prompt $ ? (Vedi questo .)
G-Man dice 'Reinstate Monica' il

Aggiunto \ $ alla fine, grazie. era perché normalmente mostro anche il mio ramo git ma questo è troppo dettaglio per qui
Michael Durrant,

1
Che cosa? Nessuna newline? No SGR0?
G-Man dice "Ripristina Monica" il

Aggiunto il linefeed
Michael Durrant,

3

Creato ~ / .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\$ "

Aggiunto nel mio ~ / .bash_profile:

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

L'output è:

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

1

Non è una soluzione per abbreviare i percorsi lunghi, ma un modo conveniente per ottenere una panoramica migliore mantenendo tutte le informazioni sul percorso visibili è l'aggiunta di una nuova riga prima dell'ultimo carattere. In questo modo il cursore si avvia sempre nella stessa colonna, anche se il percorso è abbastanza lungo da avvolgere, ma le finestre della console dovrebbero essere abbastanza alte da non scorrere le righe precedenti troppo rapidamente. Ho rimosso i codici colore per maggiore chiarezza:

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

1

Lo uso, si avvolge su più righe e rientri per la lunghezza, user@hostquindi presuppone che la corrente PS1sia effettivamente ' \u@\h:\w$'. Non tronca il percorso e si adatta alla larghezza corrente del terminale. Si divide solo il percorso /, quindi non si occupa elegantemente di directory molto lunghe (ma conserva gli spazi per la selezione / copia). Assicurati di avere sempre almeno 20 caratteri di spazio disponibile per l'input.

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

Funziona togliendo la magia \w(solo \w$per questo) PS1e sostituendola con $PWD, quindi avvolgendola come una semplice serie di personaggi. Si ricalcola PS1ogni volta dal valore originale in cui viene salvato _PS1, questo significa che vengono conservati anche gli escape "invisibili", la mia stringa di prompt originale completa per xterme prompt in grassetto:

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

E il risultato finale in un terminale a 80 colonne:

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$ _

Funziona da bash-3.2 come printf -v varviene utilizzato. A causa di varie complessità , sarà necessario un aggiustamento per altre variazioni di PS1.

(Il percorso nella barra del titolo di xterm non è né racchiuso né abbreviato, cosa che potrebbe essere fatta incorporando una delle altre risposte qui nella funzione sopra.)


0

In alternativa, nel mio .zshrc abbrevia la prima lettera di ogni directory se la larghezza del pixel supera una certa larghezza:

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

diventa:

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

Ecco la funzione zsh per farlo:

     # 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

In realtà lo uso per aggiornare il titolo del terminale in modo che, con più schede, riesco a tenere dritto quale scheda è quale. Il completo .zshrc per fare questo è qui .

Questo è molto utile in quanto mantiene il contesto e in zsh consente di completare rapidamente una directory nello stesso formato. (es. digitando cd /h/m/s/<tab>si completerà automaticamente in cd /home/mydirectory1/second_directory)


Come si applica alla domanda posta dall'OP, su come definire il prompt di PS1?
Anthon,

Modificato per chiarezza, $ t diventa PS1
Richard

0

Prova a usare questo script Python . Taglia le singole sezioni del nome del percorso, esattamente come volevi nella tua domanda. Utilizza anche le ellissi unicode che occupano solo una colonna anziché tre.

Esempio di output per il tuo percorso (quando viene dato un limite di 30 caratteri):

/home/mydir…/second…/my_actua

Vale la pena notare che questa soluzione gestisce correttamente Unicode nei nomi di directory utilizzando wcswidth. ${#PWD}, che sono state utilizzate da altre risposte, giudicheranno erroneamente l'ampiezza visiva di qualsiasi percorso contenente i caratteri UTF-8.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.