Prompt do bash compacto ao usar uma árvore de diretórios / nome de arquivo

16

Em um sistema com o Ubuntu 14.04 e bash , eu tenho a variável PS1 terminando com o seguinte conteúdo:

\u@\h:\w\$

para que o prompt seja exibido como

user@machinename:/home/mydirectory$

Às vezes, no entanto, o diretório atual tem um nome longo ou está dentro de diretórios com nomes longos, para que o prompt pareça

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

Isso preencherá a linha no terminal e o cursor irá para outra linha, o que é irritante.

Eu gostaria de obter algo como

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

Existe uma maneira de definir a variável PS1 para "encapsular" e "compactar" o nome do diretório, para nunca exceder um certo número de caracteres, obtendo um prompt mais curto?

    
por BowPark 28.02.2016 / 12:02

7 respostas

16

Primeiro, você pode simplesmente querer alterar o \w com \W . Dessa forma, apenas o nome do diretório atual é impresso e não todo o caminho:

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 $ 

Isso ainda não será suficiente se o próprio nome do diretório for muito longo. Nesse caso, você pode usar a variável PROMPT_COMMAND para isso. Esta é uma variável bash especial cujo valor é executado como um comando antes de cada prompt ser mostrado. Portanto, se você definir isso para uma função que defina o prompt desejado com base no comprimento do caminho do seu diretório atual, você poderá obter o efeito desejado. Por exemplo, adicione essas linhas ao seu ~/.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="\[3[01;33m\]\u@\h\[3[01;34m\] ${left}...${right} \$\[3[00m\] "
        else
                PS1="\[3[01;33m\]\u@\h\[3[01;34m\] \w \$\[3[00m\] "
        fi


}
PROMPT_COMMAND=get_PS1

O efeito é assim:

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 $ 
    
por 28.02.2016 / 13:00
10

Adicionar um retorno de personagem é a minha principal solução para isso

Então, meu prompt (que também contém outras coisas, tornando-o ainda mais longo) é assim:

Vocênotaráqueo$estásendoretornadocomoumanovalinha

Euconsigoissocom

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

Observe que, embora em uma linha separada, as árvores de diretórios super longas, como

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails são encurtados para

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

i.e. "top 3 diretórios / _ / bottom dois diretórios", que geralmente é o que me interessa

Isso garantirá que a linha nunca fique muito longa devido ao comprimento da árvore de diretórios. Se você quiser sempre a árvore de diretórios completa, ajuste apenas LOCATION, ou seja,

LOCATION=' \[3[01;34m\]'pwd''
    
por 28.02.2016 / 17:43
3

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

Adicionado no meu ~ / .bash_profile:

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

A saída é:

user@machinename:/home/mydirectory1/...another_long_name$
    
por 28.02.2016 / 13:54
1

Não é uma solução para encurtar caminhos longos, mas uma maneira conveniente de obter uma visão geral melhor, mantendo todas as informações de caminho visíveis, está adicionando uma nova linha antes do último caractere. Dessa forma, o cursor começa sempre na mesma coluna, mesmo que o caminho seja longo o suficiente para se contornar, mas as janelas do console devem ser altas o suficiente para não rolarem as linhas anteriores muito rapidamente. Eu removi os códigos de cor para mais clareza:

murphy@seasonsend:~
$ echo $PS1
\u@\h:\w\n\$
murphy@seasonsend:~
$ 
    
por 28.02.2016 / 12:58
1

Eu uso isso, ele envolve várias linhas e recuos pelo comprimento de user@host , então assume que o% atualPS1 é efetivamente ' \u@\h:\w$ '. Ele não trunca o caminho e se adapta à largura do terminal atual. Ele apenas divide o caminho em / , por isso não lida elegantemente com diretórios muito longos (mas preserva espaços para seleção / cópia). Isso garante que você sempre tenha pelo menos um espaço de 20 caracteres disponível para 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

Isso funciona tirando a mágica \w (corresponde apenas a \w$ para isso) de PS1 e substituindo-a por $PWD e, em seguida, envolvendo-a como uma cadeia simples de caracteres. Ele recomputa PS1 a cada vez do valor original que é salvo em _PS1 , isso significa que as saídas "invisíveis" também são preservadas, minha string de prompt original completa para xterm e prompt de negrito:

PS1="\[3]0;\u@\h:\w
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$ _
7\]\[$(tput bold)\]\u@\h\[$(tput sgr0)\]:\w$ "

E o resultado final em um terminal de 80 colunas:

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

Isso funciona do bash-3.2 como printf -v var é usado. Devido a várias complexidades , será necessário algum ajuste para outras variações de PS1 .

(O caminho na barra de título xterm não é encapsulado nem abreviado, algo que poderia ser feito incorporando uma das outras respostas aqui na função acima.)

    
por 29.02.2016 / 12:29
0

Como alternativa, no meu .zshrc, abreviado para a primeira letra de cada diretório, se a largura do pixel for superior a uma determinada largura:

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

torna-se:

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

Aqui está a função zsh para fazer isso:

     # get the path
     t='print -P "%m:%~"';
     t='echo $t | sed -r 's/([^:])[^:]*([0-9][0-9]):|([^:])[^:]*([^:]):/:/'';
     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/\/\(.\)[^\/][^\/]*\//\/\//'';
       t1="${t//[^ijlIFT]}";
       t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
       t3="${t//[^ABEKPSVXYCDHNRUw]}";
       t4="${t//[^GoQMmW]}";
     };

     PS1=$t

Na verdade, eu uso isso para atualizar o título do terminal para que, com várias guias, eu possa manter em linha reta qual guia é qual. O .zshrc completo para fazer isso é aqui .

Isso é muito útil, pois mantém o contexto e, em zsh, permite que você tab rapidamente complete um diretório no mesmo formato. (por exemplo, digitar cd /h/m/s/<tab> será preenchido automaticamente em cd /home/mydirectory1/second_directory )

    
por 28.02.2016 / 20:22
0

Tente usar este script Python . Ele corta seções individuais do nome do caminho, exatamente como você queria na sua pergunta. Ele também usa as reticências unicode que ocupam apenas uma coluna em vez de três.

Exemplo de saída para o seu caminho (quando determinado um limite de 30 caracteres):

/home/mydir…/second…/my_actua…

É interessante notar que essa solução manipula corretamente o Unicode em nomes de diretório usando wcswidth . ${#PWD} , que outras respostas usaram, irá julgar mal a largura visual de qualquer caminho que contenha caracteres UTF-8.

    
por 28.02.2016 / 15:57