Questão Bash prompt: como ter as iniciais do caminho do diretório


Eu normalmente tenho apenas o nome do diretório atual no meu prompt bash (PS1='\u@\h:\W$ '), então se eu estou em ~/projects/superapp/src/ Eu recebo:

hamish@host:src$ 

No entanto, gostaria de ter uma indicação do caminho completo sem ter o caminho completo. Eu vi capturas de tela em que as pessoas teriam

hamish@host:~/p/s/src$ 

se no diretório de exemplo acima. Então, qual valor do PS1 daria isso? Ou, na falta disso, qual script eu preciso na minha .bashrc produzir isso?


4


origem


Essa é uma ótima pergunta, mas também é uma duplicata exata de uma pergunta (já respondida) no Stack Overflow: stackoverflow.com/questions/1616678/bash-pwd-shortening - Telemachus
Não é realmente uma cópia exata, embora seja semelhante. Mas olhando através disso eu não posso ver exatamente como fazer o que eu quero - o que não é um tamanho fixo, mas apenas iniciais. Eu posso ter uma chance e postar a resposta aqui se eu tiver sucesso. - Hamish Downer
Justo. Eu postei uma resposta abaixo, com base nesse tópico. - Telemachus
É também uma duplicata de este. - Dennis Williamson
@Telemachus - é bom se referir a uma solução de outro site, mas não há motivo para que não exista uma dúvida em ambos os sites, se é sobre ambos os tópicos. Esta questão está no tópico sobre superusuário, pode e deve ser respondida aqui. - Gnoupi


Respostas:


Ok, fiquei curioso, então aqui está uma solução:

  1. Primeiro, crie uma função usando um ligeiro ajuste de A resposta de William Pursell ao SO pergunta Eu linko no meu comentário acima.
  2. Em seguida, coloque isso no seu $ PS1 como \$(function_name) no local apropriado.

Como um exemplo:

short_pwd() {
    cwd=$(pwd | perl -F/ -ane 'print join( "/", map { $i++ < @F - 1 ?  substr $_,0,1 : $_ } @F)')
    echo -n $cwd
}
# later in your .bashrc
PS1="\u \$(short_pwd) \$ "

Espero que alguém mais habilidoso no Bash-scripting do que eu possa sugerir maneiras de limpar a função, mas isso deve lhe dar uma idéia de como usar a saída de outro comando (ou função Bash) em um prompt. Veja também aqui: http://www.linux.org/docs/ldp/howto/Bash-Prompt-HOWTO/x279.html

Com base no seu comentário, observei novamente e percebi que minha solução precisava ser citada em dobro. Se você citar uma dessas funções, ela não funcionará.


2



Eu não sei perl então não posso julgar a solução geral, mas eu acho que você teria que editá-lo para usar PROMPT_COMMAND como na minha solução, caso contrário PS1 será definido quando você iniciar o bash e não será alterado quando você alterar o diretório. - Hamish Downer
@Hamish Não, está incorreto. Isso muda conforme você cd. Eu estou usando agora. (E isso não é uma coisa do Perl. Tem a ver com o funcionamento do PS1. Você pode ter informações dinâmicas lá em uma função via \$(function). - Telemachus
@Hamish Mas você me ajudou a ver que eu precisava de aspas duplas, não tão simples quanto eu escrevi originalmente. O prompt que estou testando aqui envolve escapes de cor e é mais complexo, e eu acidentalmente simplifiquei usando aspas simples. Desculpa. - Telemachus
ah interessante, eu obviamente preciso aprender um pouco mais sobre o bash ... - Hamish Downer


Eu gosto da abordagem do meowsqueak, tentando ficar no bash para o desempenho. Mas eu queria que meu caminho abreviasse nomes longos de diretórios para um caractere.

me@comp:~ $ cd my/path/haslongnames/
me@comp:~my/p/h $

Isso é baseado na solução do meowsqueak. Ele pode suportar algumas melhorias / mais recursos, mas resolve o problema básico sem disparar o sed.

Isto está em um arquivo executável, por exemplo ~ / bin / ps1

# set this to whatever you want:
MAX_PWD_LENGTH=30
function shorten_pwd
{
    # This function ensures that the PWD string does not exceed $MAX_PWD_LENGTH characters
    PWD=$(pwd)

    # determine part of path within HOME, or entire path if not in HOME
    RESIDUAL=${PWD#$HOME}

    # compare RESIDUAL with PWD to determine whether we are in HOME or not
    if [ X"$RESIDUAL" != X"$PWD" ]
    then
        PREFIX="~"
    fi

    # check if residual path needs truncating to keep total length below MAX_PWD_LENGTH
    NORMAL=${PREFIX}${RESIDUAL}
    if [ ${#NORMAL} -ge $(($MAX_PWD_LENGTH)) ]
    then
        newPWD=${PREFIX}
        OIFS=$IFS
        IFS='/'
        bits=$RESIDUAL
        for x in $bits
        do
            if [ ${#x} -ge 3 ]
            then
                NEXT="/${x:0:1}"
            else
                NEXT="$x"
            fi
            newPWD="$newPWD$NEXT"
        done

        IFS=$OIFS
    else
        newPWD=${PREFIX}${RESIDUAL}
    fi

    # return to caller
    echo $newPWD
}
export PS1="\u@\h:$(shorten_pwd) $ "

No meu .bash_profile eu então tenho

PROMPT_COMMAND="source $HOME/bin/ps1"

3



Você pode por favor explicar como a função não se queixa na linha: RESIDUAL=${PWD#$HOME}  até mesmo o sintaxe highlighter diz que é funky com o # comment - stagl
Honestamente, @stagl, faz anos que eu uso esse aviso. Não me lembro muito de por que isso funciona. : / - leff
Termo aditivo. Apenas achei isso enquanto pesquisava algo mais. gnu.org/software/bash/manual/html_node/…  "A palavra é expandida para produzir um padrão exatamente como na expansão de nome de arquivo (consulte Expansão de nome de arquivo). Se o padrão corresponder ao início do valor expandido do parâmetro, o resultado da expansão será o valor expandido do parâmetro com o menor padrão de correspondência (O caso)" - leff


Eu reescrevi isso recentemente, baseado em outro script que eu escrevi anos atrás - este é otimizado para rodar o mais rápido possível, para evitar garfos caros. Foi quase 8x mais rápido que minha função antiga que usava o awk / sed.

Produz bons resultados. Ele mantém a parte pwd do prompt em no máximo MAX_PWD_LENGTH caracteres e, se você estiver em um subdiretório de $ HOME, isso também ficará claro:

Exemplos:

pc770-ubu:~ $ cd ~/a/b/c
pc770-ubu:~/a/b/c $ cd d/e/f
pc770-ubu:~/a/b/c/d/e/f $ cd g
pc770-ubu:~/a/b/c/d/e/f/g $ cd h
pc770-ubu:~/a/b/c/d/e/f/g/h $ cd i
pc770-ubu:~/a/b/c/d/e/f/g/h/i $ cd j
pc770-ubu:~/a/b/c/d/e/f/g/h/i/j $ cd k
pc770-ubu:~/a/b/c/d/e/f/g/h/i/j/k $ cd l
pc770-ubu:~../c/d/e/f/g/h/i/j/k/l $ cd m
pc770-ubu:~../d/e/f/g/h/i/j/k/l/m $ cd n
pc770-ubu:~../e/f/g/h/i/j/k/l/m/n $ cd o
pc770-ubu:~../f/g/h/i/j/k/l/m/n/o $ cd /tmp/a/b/c/d/e/f
pc770-ubu:/tmp/a/b/c/d/e/f $ cd g
pc770-ubu:/tmp/a/b/c/d/e/f/g $ cd h
pc770-ubu:/tmp/a/b/c/d/e/f/g/h $ cd i
pc770-ubu:/tmp/a/b/c/d/e/f/g/h/i $ cd j
pc770-ubu:/../a/b/c/d/e/f/g/h/i/j $ cd k
pc770-ubu:/../b/c/d/e/f/g/h/i/j/k $ cd l
pc770-ubu:/../c/d/e/f/g/h/i/j/k/l $ cd m
pc770-ubu:/../d/e/f/g/h/i/j/k/l/m $ cd
pc770-ubu:~ $ 

A função bash (chamar isso ao construir sua variável PS1):

# set this to whatever you want:
MAX_PWD_LENGTH=20

function shorten_pwd
{
    # This function ensures that the PWD string does not exceed $MAX_PWD_LENGTH characters
    PWD=$(pwd)

    # if truncated, replace truncated part with this string:
    REPLACE="/.."

    # determine part of path within HOME, or entire path if not in HOME
    RESIDUAL=${PWD#$HOME}

    # compare RESIDUAL with PWD to determine whether we are in HOME or not
    if [ X"$RESIDUAL" != X"$PWD" ]
    then
        PREFIX="~"
    fi

    # check if residual path needs truncating to keep total length below MAX_PWD_LENGTH
    # compensate for replacement string.
    TRUNC_LENGTH=$(($MAX_PWD_LENGTH - ${#PREFIX} - ${#REPLACE} - 1))
    NORMAL=${PREFIX}${RESIDUAL}
    if [ ${#NORMAL} -ge $(($MAX_PWD_LENGTH)) ]
    then
        newPWD=${PREFIX}${REPLACE}${RESIDUAL:((${#RESIDUAL} - $TRUNC_LENGTH)):$TRUNC_LENGTH}
    else
        newPWD=${PREFIX}${RESIDUAL}
    fi

    # return to caller
    echo $newPWD
}

EDIT: bug fixo com comprimento absoluto de string


2





PROMPT_DIRTRIM=3

forçará \ w a expandir para o máximo de três elementos à direita do caminho do diretório de trabalho atual, com o precedente, se houver, substituído por "...".


2





Basta adicionar isso (e editar como quiser) ao seu .bashrc:

PS1='\u@\h:`pwd | sed -e "s/\/\(.\)[^\/]\+/\/\1/g"`\$ '

1



Eu tentei isso, mas infelizmente isso define o valor de PS1uma vez quando você começar o bash e não irá atualizá-lo depois disso. Então você vai mudar de diretório e seu prompt não vai mudar - eu cometi esse erro e, em seguida, estava jogando e tive que coçar a cabeça para resolvê-lo. Veja minha (editado) resposta para uma maneira de contornar isso usando PROMPT_COMMAND - Hamish Downer
Não, funciona para mim, muda sempre. - cYrus
E echo $PS1 dá: \ u @ \ h: 'pwd | sed -e "s / \ / (.) [^ \ /] \ + / \ / \ 1 / g" '\ $ então não é codificado na variável (não sei como sobrescrever essa marcação, apenas substitua 'por `). - cYrus
Ah ok. Eu vou ler mais um pouco, obrigado por explicar. - Hamish Downer


Eu fiz um pouco mais de googling nesse meio tempo, e depois de passar por alguns termos de pesquisa, me deparei com Este artigo que menciona o concha de peixe faz o que eu quero e forneceu uma maneira de fazer isso. Eu o modifiquei para que o usuário e o host também sejam exibidos e acabem com o razoavelmente sucinto:

# abbreviate the dir path
PROMPT_COMMAND='CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'
PS1="\u@\h:\$CurDir \$ "

Basicamente toda vez que o prompt está prestes a ser exibido, PROMPT_COMMAND ajustarei $CurDir para o caminho do diretório abreviado que é então usado em $PS1. Lembre-se de que, se PROMPT_COMMAND está definido em outro lugar, você precisará adicionar o comando acima ao final daquele, precedido por um ;. Então, para o exemplo comum de definir o título de um xterm, você terminaria com

PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD/$HOME/~}\007"; CurDir=`pwd|sed -e "s!$HOME!~!"|sed -re "s!([^/])[^/]+/!\1/!g"`'

Algumas outras maneiras possíveis de abreviar o caminho podem ser encontradas:


1





Outra versão do @Telemachus short_pwd (), sem requisito de perl.

short_pwd() {
cwd=$(pwd)

if [ $cwd == $HOME ]; then echo -n "~"; return; fi 
if [ $cwd == "/" ]; then echo -n "/"; fi 

for l in $(echo $cwd | tr "/" "\n"); do 
    echo -n "/"
    echo -n ${l:0:1}
done
echo -n ${l:1}
}

1





Tente isto:

PS1='$(pp="$PWD/" q=${pp/#"$HOME/"/} p=${q%?};((${#p}>19))&&echo "${p::9}…${p:(-9)}"||echo "$p") \$'

Transforma

~/.vim/bundle/ack.vim/plugin

para

.vim/bund…im/plugin

transfrom

/usr/share/doc/xorg-x11-font-utils-7.5/

para

/usr/shar…utils-7.5

E quando $PWD igual a $HOME, não mostre nada.

Bônus: você pode modificar o número de tamanho para atender às suas necessidades.


0