Question Invite Bash: comment avoir les initiales du chemin de répertoire


Je n'ai normalement que le nom du répertoire actuel dans mon invite bash (PS1='\u@\h:\W$ '), donc si je suis dans ~/projects/superapp/src/ Je reçois:

hamish@host:src$ 

Cependant, je voudrais avoir une indication du chemin complet sans avoir le chemin complet. J'ai vu des screenshots où les gens auraient

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

si dans l'exemple de répertoire ci-dessus. Alors quelle valeur de PS1 donnerait cela? Ou à défaut, quel script ai-je besoin dans mon .bashrc pour produire ça?


4
2017-08-24 21:34


origine


C'est une excellente question, mais c'est aussi une copie exacte d'une question (déjà répondue) sur Stack Overflow: stackoverflow.com/questions/1616678/bash-pwd-shortening - Telemachus
Ce n'est pas réellement une copie exacte, même si elle est similaire. Mais en regardant à travers cela, je ne peux pas facilement voir exactement comment faire ce que je veux - ce qui n'est pas une longueur fixe, mais juste des initiales. Je pourrais essayer et poster la réponse ici si je réussis. - Hamish Downer
C'est suffisant. J'ai posté une réponse ci-dessous, basée sur ce fil. - Telemachus
C'est aussi un duplicata de celui-là. - Dennis Williamson
@Telemachus - il est bon de se référer à une solution d'un autre site, mais il n'y a aucune raison pour qu'une question ne puisse pas exister sur les deux sites, si elle est sur le sujet des deux. Cette question est sur le sujet sur Super User, il peut et doit être répondu ici. - Gnoupi


Réponses:


Ok, je suis curieux, alors voici une solution:

  1. Tout d'abord, créez une fonction en utilisant un léger tweak de La réponse de William Pursell au SO question Je lie dans mon commentaire ci-dessus.
  2. Ensuite, mettez cela dans votre $ PS1 comme \$(function_name) à l'endroit approprié.

Par exemple:

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) \$ "

J'ai bon espoir que quelqu'un de plus expérimenté que Bash-Scripting puisse suggérer des moyens de nettoyer la fonction, mais cela devrait vous donner une idée de la manière d'utiliser la sortie d'une autre commande (ou fonction Bash) dans une invite. Voir aussi ici: http://www.linux.org/docs/ldp/howto/Bash-Prompt-HOWTO/x279.html

Sur la base de votre commentaire, j'ai regardé à nouveau et réalisé que ma solution devait être cotée en double. Si vous citez une telle fonction, elle ne fonctionnera pas du tout.


2
2017-08-24 22:13



Je ne sais pas perl donc ne peut pas juger de la solution générale, mais je pense que vous devriez le modifier pour l'utiliser PROMPT_COMMAND comme dans ma solution, sinon PS1 sera défini lorsque vous démarrez bash et ne changera pas lorsque vous changez de répertoire. - Hamish Downer
@Hamish Non, c'est incorrect. Cela change comme vous cd. Je l'utilise maintenant. (Et ce n’est pas une chose Perl. Cela a à voir avec le fonctionnement de PS1. Vous pouvez y avoir des informations dynamiques dans une fonction via \$(function). - Telemachus
@Hamish Mais vous m'avez aidé à voir que j'avais besoin de doubles citations, pas de simples comme je l'ai écrit à l'origine. L'invite que je teste ici implique des échappements de couleurs et est plus complexe, et je l'ai accidentellement simplifié en utilisant des guillemets simples. Pardon. - Telemachus
ah intéressant, j'ai évidemment besoin d'en apprendre un peu plus sur bash ... - Hamish Downer


J'aime l'approche de meowsqueak, en essayant de rester en bas pour la performance. Mais je voulais que mon chemin abrégé des noms de répertoires longs en un seul caractère.

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

Ceci est basé sur la solution de meowsqueak. Il pourrait supporter quelques améliorations / fonctionnalités mais il résout le problème de base sans déclencher sed.

Ceci est dans un fichier exécutable, par exemple ~ / 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) $ "

Dans mon fichier .bash_profile, j'ai

PROMPT_COMMAND="source $HOME/bin/ps1"

3
2017-08-03 17:01



Pouvez-vous s'il vous plaît expliquer comment la fonction ne se plaint pas sur la ligne: RESIDUAL=${PWD#$HOME}  même le surligneur de syntaxe dit qu'il est génial avec le commentaire # - stagl
Honnêtement @stagl, cela fait des années que j'ai utilisé cette invite. Je ne me souviens pas beaucoup de la raison pour laquelle cela fonctionne. : / - leff
Addenda. Je viens de trouver ça en recherchant autre chose. gnu.org/software/bash/manual/html_node/ ...  "Le mot est développé pour produire un motif comme dans l'extension de nom de fichier (voir Extension de nom de fichier). Si le modèle correspond au début de la valeur étendue du paramètre, le résultat de l'extension est la valeur étendue du paramètre avec le motif correspondant le plus court (l'affaire)" - leff


Je l'ai réécrit récemment, sur la base d'un autre script que j'ai écrit il y a quelques années - celui-ci est optimisé pour s'exécuter autant que possible dans bash, afin d'éviter les fourches coûteuses. C'était presque 8 fois plus rapide que mon ancienne fonction qui utilisait awk / sed.

Cela produit de bons résultats. Il conserve la partie pwd de l'invite à des caractères MAX_PWD_LENGTH au maximum, et si vous êtes dans un sous-répertoire de $ HOME, cela est également clair:

Exemples:

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:~ $ 

La fonction bash (appelez cela lors de la construction de votre variable 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: correction d'un bug avec une longueur de chaîne absolue


2
2017-08-25 02:27





PROMPT_DIRTRIM=3

forcera \ w à développer le maximum de trois éléments de fin du chemin de répertoire de travail en cours, avec le précédent, le cas échéant, remplacé par "...".


2
2018-04-16 14:28





Ajoutez simplement ceci (et éditez-le comme vous voulez) à votre .bashrc:

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

1
2017-08-24 22:29



J'ai essayé cela, mais malheureusement, il définit la valeur de PS1 une fois lorsque vous démarrez bash et ne le mettra pas à jour après cela. Donc, vous allez changer de répertoire et votre message ne changera pas - j'ai fait cette erreur puis je jouais et j'ai dû me gratter la tête pour le résoudre. Voir ma réponse (édité) pour un moyen de contourner ce problème en utilisant PROMPT_COMMAND - Hamish Downer
Non, ça marche pour moi, ça change à chaque fois. - cYrus
Et echo $PS1 donne: \ u @ \ h: 'pwd | sed -e "s / \ / (.) [^ \ /] \ + / \ / \ 1 / g" '\ $ donc ce n'est pas codé en dur dans la variable (je ne sais pas comment écraser ce balisage, juste remplacer 'avec `). - cYrus
Ah d'accord. Je vais en lire plus, merci de m'avoir expliqué. - Hamish Downer


J'ai fait un peu plus de googler entre temps, et après avoir parcouru quelques termes de recherche, je suis tombé sur Cet article qui mentionne le coquille de poisson fait ce que je veux et fournit un moyen de le faire. Je l'ai modifié pour que l'utilisateur et l'hôte s'affichent également et se retrouvent avec le résultat le plus succinct:

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

Fondamentalement, chaque fois que l'invite est sur le point d'être affichée, PROMPT_COMMAND va fixer $CurDir au chemin de répertoire abrégé qui est ensuite utilisé dans $PS1. N'oubliez pas que si PROMPT_COMMAND est défini ailleurs, vous devrez ajouter la commande ci-dessus à la fin de celle-ci, précédée d'un ;. Donc, pour l'exemple commun de définir le titre d'un xterm, vous vous retrouveriez avec

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

On peut trouver d'autres moyens possibles pour abréger le chemin:


1
2017-08-24 22:38





Une autre version de @Telemachus short_pwd (), sans exigence 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
2017-09-13 20:05