Mensaje bash compacto cuando se utiliza un árbol de directorio / nombre de archivo

16

En un sistema con Ubuntu 14.04 y bash, tengo la PS1variable que termina con los siguientes contenidos:

\u@\h:\w\$

para que el mensaje aparezca como

user@machinename:/home/mydirectory$

A veces, sin embargo, el directorio actual tiene un nombre largo, o está dentro de directorios con nombres largos, de modo que el indicador se ve como

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

Esto llenará la línea en la terminal y el cursor irá a otra línea, lo cual es molesto.

En cambio, me gustaría obtener algo como

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

¿Hay alguna manera de definir la PS1variable para "ajustar" y "compactar" el nombre del directorio, para que nunca exceda un cierto número de caracteres, obteniendo un mensaje más corto?

BowPark
fuente
1
Afortunadamente, recuerdo dónde leí cómo personalizar el indicador de comandos de shell: tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html Gracias a Giles Orr, autor de Bash Prompt HOWTO y a las personas que contribuyeron.
surgió
Ver también unix.stackexchange.com/a/216871/117549 (basado en ksh, pero idea similar)
Jeff Schaller

Respuestas:

16

En primer lugar, es posible que simplemente desee cambiar el \wcon \W. De esa manera, solo se imprime el nombre del directorio actual y no su ruta completa:

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 $ 

Es posible que aún no sea suficiente si el nombre del directorio en sí es demasiado largo. En ese caso, puede usar la PROMPT_COMMANDvariable para esto. Esta es una variable bash especial cuyo valor se ejecuta como un comando antes de que se muestre cada solicitud. Entonces, si establece eso en una función que establece su solicitud deseada en función de la longitud de la ruta de acceso de su directorio actual, puede obtener el efecto que busca. Por ejemplo, agregue estas líneas a su ~/.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

El efecto se ve así:

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 $ 
terdon
fuente
10

Agregar un retorno de caracteres es mi solución principal para esto

Entonces mi aviso (que también tiene otras cosas, haciéndolo aún más largo) se ve así:

ingrese la descripción de la imagen aquí

Notarás que los $ se devuelven como una nueva línea

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

Tenga en cuenta que, aunque en una línea separada, los árboles de directorios súper largos como

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails se acortan a

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

es decir, "los 3 directorios principales / _ / dos directorios inferiores", que generalmente es lo que me importa

Esto asegurará que la línea nunca se alargue demasiado debido a la longitud del árbol de directorios. Si siempre desea el árbol de directorios completo, simplemente ajuste LOCATION, es decir

LOCATION=' \[\033[01;34m\]`pwd`'
Michael Durrant
fuente
Más información sobre el color en unix.stackexchange.com/q/124407/10043
Michael Durrant
1
¿Dónde incluye realmente su aviso $ ? (Vea esto .)
G-Man dice 'Reinstate a Monica' el
Se agregó el \ $ al final, gracias. fue porque normalmente también muestro mi rama de git, pero eso es demasiado detalle aquí
Michael Durrant
1
¿Qué? No hay nueva línea? No SGR0?
G-Man dice 'Reincorporar a Monica' el
Se agregó el salto de línea
Michael Durrant
3

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

Agregado en mi ~ / .bash_profile:

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

Salida es:

user@machinename:/home/mydirectory1/...another_long_name$
código infernal
fuente
1

No es una solución para acortar caminos largos, pero una forma conveniente de obtener una mejor visión general mientras se mantiene visible toda la información del camino, es agregar una nueva línea antes del último carácter. De esta manera, el cursor comienza siempre en la misma columna, incluso si la ruta es lo suficientemente larga como para ajustarse, pero las ventanas de la consola deben ser lo suficientemente altas como para no desplazarse demasiado rápido por las líneas anteriores. Eliminé los códigos de color para mayor claridad:

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

Utilizo esto, se envuelve en varias líneas y sangra por la longitud de user@hostlo que supone que la corriente PS1es efectiva ' \u@\h:\w$'. No trunca la ruta y se adapta al ancho actual del terminal. Solo divide la ruta /, por lo que no trata con elegancia directorios muy largos (pero conserva espacios para selección / copia). Se asegura de que siempre tenga al menos un espacio de 20 caracteres disponible para la entrada.

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

Esto funciona sacando la magia \w(coincide solo \w$con esto) PS1y reemplazándola por $PWD, luego envolviéndola como una cadena simple de caracteres. Se vuelve a calcular PS1cada vez que se guarda el valor original, lo que _PS1significa que los escapes "invisibles" también se conservan, mi cadena de solicitud original completa xtermy la solicitud en negrita:

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

Y el resultado final en un terminal de 80 columnas:

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

Esto funciona desde bash-3.2 como printf -v varse usa. Debido a diversas complejidades , necesitará algún ajuste para otras variaciones de PS1.

(La ruta en la barra de título de xterm no está ajustada ni abreviada, algo que podría hacerse incorporando una de las otras respuestas aquí en la función anterior).

Sr. púrpura
fuente
0

Como alternativa, en mi .zshrc abrevío la primera letra de cada directorio si el ancho del píxel supera un cierto ancho:

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

se convierte en:

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

Aquí está la función zsh para hacerlo:

     # 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

De hecho, uso esto para actualizar el título del terminal para que con varias pestañas, pueda mantener en claro qué pestaña es cuál. El .zshrc completo para hacer esto está aquí .

Esto es muy útil ya que mantiene el contexto y en zsh le permite completar rápidamente un directorio en el mismo formato. (por ejemplo, escribir cd /h/m/s/<tab>se completará automáticamente cd /home/mydirectory1/second_directory)

Ricardo
fuente
¿Cómo se aplica esto a la pregunta que planteó el OP, sobre cómo definir la solicitud de PS1?
Anthon
Editado para mayor claridad, $ t se convierte en PS1
Richard
0

Intenta usar este script de Python . Corta secciones individuales del nombre de la ruta, exactamente como quería en su pregunta. También utiliza los puntos suspensivos unicode que ocupan solo una columna en lugar de tres.

Ejemplo de salida para su ruta (cuando se le da un límite de 30 caracteres):

/home/mydir…/second…/my_actua

Vale la pena señalar que esta solución maneja correctamente Unicode en los nombres de directorio mediante el uso wcswidth. ${#PWD}, que otras respuestas han utilizado, juzgarán mal el ancho visual de cualquier ruta que contenga caracteres UTF-8.

Functino
fuente