web-dev-qa-db-fra.com

Bash: PS1 personnalisée avec le chemin du répertoire de travail de Nice

J'utilise Ubuntu et je suis fatigué de cette longue invite de bash lorsque je travaille avec une hiérarchie de répertoires profonde. Je voudrais donc modifier ma PS1 pour raccourcir la partie du répertoire de travail de la manière suivante:

Actuellement j'ai:

pajton@dragon:~/workspace/projects/project1/folder1/test$

et aimerait avoir:

pajton@dragon:~/workspace/.../folder1/test$

La troncature se produirait si len ($ PWD) dépasse un seuil donné. Je veux toujours garder le premier composant de chemin et au moins un dernier composant de chemin. Ensuite, si l'espace le permet, ajoutez d'autres composants en partant de la droite.

C'est ce que j'ai actuellement. Cela fonctionne, mais: 1) ne conserve pas le composant de premier chemin, 2) ne respecte pas le chemin de coupe aux limites:

pwd_length=14
pwd_symbol="..."
newPWD="${PWD/#$HOME/~}"

if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD="...$(echo -n $PWD | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")"
else
   newPWD="$(echo -n $PWD)"
fi

Et le résultat:

pajton@dragon:...sth/folder1/sample$ 

Merci d'avance!

51
pajton

Considérez ce script en utilisant awk au lieu de sed pour votre cas:

pwd_length=14
pwd_symbol="..."
newPWD="${PWD/#$HOME/~}"
if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD=$(echo -n $newPWD | awk -F '/' '{
   print $1 "/" $2 "/.../" $(NF-1) "/" $(NF)}')
fi
PS1='${newPWD}$ '

Pour votre exemple de répertoire ~/workspace/projects/project1/folder1/test, PS1 devient: ~/workspace/.../folder1/test

METTRE À JOUR

La solution ci-dessus définira votre invite, mais comme vous l'avez indiqué dans votre commentaire, elle ne modifiera PAS PS1 de manière dynamique lorsque vous changerez de répertoire. Voici donc la solution qui définira de manière dynamique PS1 lorsque vous modifierez des répertoires.

Mettez ces 2 lignes dans votre fichier .bashrc:

export MYPS='$(echo -n "${PWD/#$HOME/~}" | awk -F "/" '"'"'{
if (length($0) > 14) { if (NF>4) print $1 "/" $2 "/.../" $(NF-1) "/" $NF;
else if (NF>3) print $1 "/" $2 "/.../" $NF;
else print $1 "/.../" $NF; }
else print $0;}'"'"')'
PS1='$(eval "echo ${MYPS}")$ '

La condition if (NF > 4 && length($0) > 14) dans awk n’appliquera un traitement spécial que si votre répertoire en cours a plus de 3 répertoires en profondeur ET si la longueur de $PWD est supérieure à 14 caractères, sinon il conservera PS1 en tant que $PWD

par exemple: si le répertoire actuel est ~/workspace/projects/project1$, alors PS1 sera ~/workspace/projects/project1$

L’effet de ci-dessus dans .bashrc sera le suivant sur votre PS1:

~$ cd ~/workspace/projects/project1/folder1/test
~/workspace/.../folder1/test$ cd ..
~/workspace/.../project1/folder1$ cd ..
~/workspace/.../project1$ cd ..
~/.../projects$ cd ..
~/workspace$ cd ..
~$

Remarquez comment Prompt change lorsque je change de répertoire. Faites-moi savoir si ce n'est pas ce que vous vouliez.

45
anubhava

Pour les personnes recherchant une solution beaucoup plus simple et n'ayant pas besoin du nom du premier répertoire du chemin, Bash dispose d'une prise en charge intégrée à l'aide de la variable Prompt_DIRTRIM. De la documentation :

Prompt_DIRTRIM

Si ce paramètre est défini sur un nombre supérieur à zéro, la valeur est utilisée comme nombre de composants de répertoire de fin à conserver lors du développement des échappements de chaînes d'invites\w et\W (voir Impression d'une invite). Les caractères supprimés sont remplacés par un Ellipsis. 

Par exemple:

~$ mkdir -p a/b/c/d/e/f
~$ cd a/b/c/d/e/f
~/a/b/c/d/e/f$ export Prompt_DIRTRIM=2
~/.../e/f$ Prompt_DIRTRIM=3
~/.../d/e/f$ 

Inconvénient: Cela dépend du niveau de répertoire, pas de la longueur du chemin, ce que vous ne voudrez peut-être pas.

Upside: C'est très simple. Ajoutez simplement export Prompt_DIRTRIM=2 à votre .bashrc.

113
imgx64

C’est ce que j’utilise à partir des solutions d’anubhava. Il définit à la fois l'invite et le titre de la fenêtre. Le script awk est plus lisible et peut donc être modifié/personnalisé facilement.

Le chemin sera plié s'il y a plus de 16 caractères et 4 niveaux de profondeur. En outre, il indiquera également dans ... combien de répertoires ont été pliés, ce qui vous donne une idée de la profondeur du chemin, c'est-à-dire: ~/usr/..4../path2/path1 indique que 4 niveaux ont été pliés. 

# define the awk script using heredoc notation for easy modification
MYPSDIR_AWK=$(cat << 'EOF'
BEGIN { FS = OFS = "/" }
{ 
   sub(ENVIRON["HOME"], "~");
   if (length($0) > 16 && NF > 4)
      print $1,$2,".." NF-4 "..",$(NF-1),$NF
   else
      print $0
}
EOF
)

# my replacement for \w Prompt expansion
export MYPSDIR='$(echo -n "$PWD" | awk "$MYPSDIR_AWK")'

# the fancy colorized Prompt: [0 user@Host ~]$
# return code is in green, user@Host is in bold/white
export PS1='[\[\033[1;32m\]$?\[\033[0;0m\] \[\033[0;1m\]\u@\h\[\033[0;0m\] $(eval "echo ${MYPSDIR}")]$ '

# set x/ssh window title as well
export Prompt_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")\007"'

Voici à quoi ça ressemble en action. Le vert 0 est le code retour de la dernière commande:

 enter image description here

9
raychi
echo -n $PWD | sed -re "s|(~?/[^/]*/).*(.{$pwd_length})|\1...\2|"

sed avec -r uniquement pour des raisons de commodité, permet d'omettre les barres obliques inverses avant les parenthèses et "|" comme délimiteur uniquement pour des raisons de commodité également - car nous souhaitons utiliser la barre oblique à l'intérieur de la commande. Je suppose que votre maison est affichée aussi ~, donc ~/foo/bar/baz/devrait se terminer par ~/foo /.../ baz et/foo/bar/baz/as /foo/.../baz /. 

Nous prenons donc un optionnel ~, suivi de slash, name, slash comme\1, puis quelque chose, puis du reste comme\2. 

5
user unknown

Une autre approche, utilisant toujours sed et awk pour générer l’invite. Ceci convertira votre répertoire $HOME en ~, vous montrera votre répertoire racine, votre niveau le plus bas (répertoire courant) et son parent, séparés par .. pour chaque répertoire situé entre les deux.

Dans votre .bashrc (ou .bash_profile sous OS X):

function generate_pwd {
  pwd | sed s.$HOME.~.g | awk -F"/" '
  BEGIN { ORS="/" }
  END {
  for (i=1; i<= NF; i++) {
      if ((i == 1 && $1 != "") || i == NF-1 || i == NF) {
        print $i
      }
      else if (i == 1 && $1 == "") {
        print "/"$2
        i++
      }
      else {
        print ".."
      }
    }
  }'
}
export PS1="\$(generate_pwd) -> "

Le script utilise la variable NF construite par awk (nombre de champs) et les variables de position ($1, $2 ...) pour imprimer chaque champ (nom du répertoire) séparé par la variable ORS (séparateur d'enregistrement de sortie). Il réduit les répertoires internes en .. dans votre invite.

Exemple d'utilisation:

~/ -> cd Documents/
~/Documents/ -> cd scripts/
~/Documents/scripts/ -> cd test1/
~/../scripts/test1/ -> cd test2
~/../../test1/test2/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2
~/../../test1/test2/ -> cd test3/
~/../../../test2/test3/ -> cd test4/
~/../../../../test3/test4/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2/test3/test4
~/../../../../test3/test4/ -> cd /usr/
/usr/ -> cd local/
/usr/local/ -> cd etc/
/usr/local/etc/ -> cd openssl/
/usr/../etc/openssl/ -> cd private/
/usr/../../openssl/private/ ->
3
Brandon

Outre la solution intégrée à bash utilisant Prompt_DIRTRIM, vous pouvez essayer $(pwd | tail -c16), ce qui est un peu plus simple que la plupart des autres réponses, mais donne uniquement les 16 derniers caractères du répertoire en cours. Bien sûr, remplacez 16 par le nombre de votre choix.

1
Sebastian Mach

Pas si différent des solutions précédentes. Cependant, peut-être un peu plus lisible/éditable. Cependant, aucune solution à la limite de nom de dossier, se concentrant uniquement sur la longueur de l'invite.

### SET MY Prompt ###
if [ -n "$PS1" ]; then
    # A temporary variable to contain our Prompt command
    NEW_Prompt_COMMAND='
        pwd_short=${PWD/#$HOME/\~};
        if [ ${#pwd_short} -gt 53 ]; then
            TRIMMED_PWD=${pwd_short: 0: 25}...${pwd_short: -25}
        else
            TRIMMED_PWD=${pwd_short}
        fi
    '

    # If there's an existing Prompt command, let's not 
    # clobber it
    if [ -n "$Prompt_COMMAND" ]; then
        Prompt_COMMAND="$Prompt_COMMAND;$NEW_Prompt_COMMAND"
    else
        Prompt_COMMAND="$NEW_Prompt_COMMAND"
    fi

    # We're done with our temporary variable
    unset NEW_Prompt_COMMAND

    # Set PS1 with our new variable
    # \h - hostname, \u - username
    PS1='\u@\h: $TRIMMED_PWD\$ '
fi

ajouté au fichier .bashrc . Toutes les parties de l'invite sont mises à jour correctement. La première partie est raccourcie si vous vous trouvez dans votre répertoire personnel. Exemple:

utilisateur @ ordinateur: ~/misc/projs/solardrivers ... src/com/mycompany/handles $

0
karnbo

Pourquoi ne pas simplement utiliser ${string:position:length}? Vous pouvez faire ${string:-$max_chars} pour avoir le dernier ${max_chars} de la chaîne. 

notez la valeur négative

0
Naus Caligo

https://github.com/chrissound/SodiumSierraStrawberry

Vous permet de tronquer un chemin tel que:

De:/home/sodium/Projets/Personnel/Sierra/Super/Long/Path/HolyAvacado

To: »Projets/Sie…/Sup…/Lon…/Pat…/HolyAvacado /

0
Chris Stryczynski
generatePwd(){
  set -- "`pwd | sed -e s.${HOME}.~.g`"
  IFS="/"; declare -a array=($*)
  srt=""
  count=0
  for i in ${!array[@]}; do
      # echo ${array[i]} - $i/${#array[@]}
      if [[ $i == 0 ]]; then
        srt+=""
      Elif [[ $i == $((${#array[@]}-1)) ]] || [[ $i == $((${#array[@]}-2)) ]]; then
          srt+="/${array[i]}"
      else
        count=$((${count}+1))
      fi
  done
  if [[ $count != 0 ]]; then
    srt="${array[0]}/.$count.$srt"
  else
    srt="${array[0]}$srt"
  fi
  echo "${srt}"
}

exportation PS1

PS1="\$(generatePwd)"

Console

$ ~/.3./machine-learning/deep-learning-computer-vision
0