140 votes

Quelle est la différence entre PS1 et PROMPT_COMMAND ?

En jetant un coup d'œil à ce fil de discussion génial J'ai remarqué que certains exemples utilisent

PS1="Blah Blah Blah"

et certains utilisent

PROMPT_COMMAND="Blah Blah Blah"

(et certains utilisent les deux) pour définir l'invite dans un shell Bash. Quelle est la différence entre les deux ? Une recherche sur Stack Overflow et même un peu de recherche plus large sur Google ne me donnent pas de résultats, donc même un lien vers le bon endroit pour trouver la réponse serait apprécié.

76voto

sashang Points 4548

PROMPT_COMMAND peut contenir des instructions Bash ordinaires, tandis que la variable PS1 peut également contenir des caractères spéciaux, tels que ' \h ' pour le nom d'hôte, dans la variable.

Par exemple, voici mon invite Bash qui utilise à la fois PROMPT_COMMAND et PS1. Le code Bash de PROMPT_COMMAND détermine la branche Git dans laquelle vous vous trouvez et l'affiche à l'invite, ainsi que l'état de sortie du dernier processus exécuté, le nom d'hôte et le nom de base de l'ordinateur. pwd .

La variable RET stocke la valeur de retour du dernier programme exécuté. C'est pratique pour voir s'il y a eu une erreur et le code d'erreur du dernier programme exécuté dans le terminal. Notez le ' extérieur entourant l'expression PROMPT_COMMAND entière. Elle inclut PS1 afin que cette variable soit réévaluée chaque fois que la variable PROMPT_COMMAND est évaluée.

PROMPT_COMMAND='RET=$?;\
  BRANCH="";\
  ERRMSG="";\
  if [[ $RET != 0 ]]; then\
    ERRMSG=" $RET";\
  fi;\
  if git branch &>/dev/null; then\
    BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2);\
  fi;
PS1="$GREEN\u@\h $BLUE\W $CYAN$BRANCH$RED$ERRMSG \$ $LIGHT_GRAY";'

L'exemple de sortie ressemble à ceci dans un répertoire non-Git :

sashan@dhcp-au-122 Documents  $ false
sashan@dhcp-au-122 Documents  1 $

Et dans un répertoire Git, vous voyez le nom de la branche :

sashan@dhcp-au-122 rework mybranch $

Mise à jour

Après avoir lu les commentaires et la réponse de Bob, je pense que l'écrire comme il le décrit est mieux. C'est plus facile à maintenir que ce que j'ai écrit à l'origine ci-dessus, où la variable PS1 est définie dans la PROMPT_COMMAND, qui est elle-même une chaîne de caractères super compliquée qui est évaluée à l'exécution par Bash.

Ça marche, mais c'est plus compliqué que nécessaire. Pour être honnête, j'ai écrit cette PROMPT_COMMAND pour moi-même il y a environ 10 ans et elle a fonctionné, sans trop y penser.

Pour ceux qui sont curieux de savoir comment j'ai modifié mes choses, j'ai essentiellement placé le code de la PROMPT_COMMAND dans un fichier séparé (comme Bob l'a décrit) et j'ai ensuite fait écho à la chaîne de caractères que j'entends être PS1 :

GREEN="\[\033[0;32m\]"
CYAN="\[\033[0;36m\]"
RED="\[\033[0;31m\]"
PURPLE="\[\033[0;35m\]"
BROWN="\[\033[0;33m\]"
LIGHT_GRAY="\[\033[0;37m\]"
LIGHT_BLUE="\[\033[1;34m\]"
LIGHT_GREEN="\[\033[1;32m\]"
LIGHT_CYAN="\[\033[1;36m\]"
LIGHT_RED="\[\033[1;31m\]"
LIGHT_PURPLE="\[\033[1;35m\]"
YELLOW="\[\033[1;33m\]"
WHITE="\[\033[1;37m\]"
RESTORE="\[\033[0m\]" #0m restores to the terminal's default colour

if [ -z $SCHROOT_CHROOT_NAME ]; then
    SCHROOT_CHROOT_NAME=" "
fi
BRANCH=""
ERRMSG=""
RET=$1
if [[ $RET != 0 ]]; then
    ERRMSG=" $RET"
fi
if which git &>/dev/null; then
    BRANCH=$(git branch 2>/dev/null | grep \* |  cut -d " " -f 2)
else
    BRANCH="(git not installed)"
fi
echo "${GREEN}\u@\h${SCHROOT_CHROOT_NAME}${BLUE}\w \
${CYAN}${BRANCH}${RED}${ERRMSG} \$ $RESTORE"

Et dans mon .bashrc fichier :

function prompt_command {
    RET=$?
    export PS1=$(~/.bash_prompt_command $RET)
}
PROMPT_DIRTRIM=3
export PROMPT_COMMAND=prompt_command

2 votes

Tu pourrais raccourcir une de tes lignes : if git branch &>/dev/null ; then\ . Il redirige à la fois stdout et stderr vers /dev/null. tldp.org/LDP/abs/html/io-redirection.html

4 votes

Il n'est pas nécessaire de exporter PROMPT_COMMAND .

2 votes

Je pense que le commentaire de Ceving est tout à fait vrai pour cette réponse aussi : Don't set PS1 in PROMPT_COMMAND! Set variables in PROMPT_COMMAND and use them in PS1

71voto

Scott Thomson Points 281

Depuis la page de documentation de GNU Bash ( Manuel de référence Bash ) :

PROMPT_COMMAND
    If set, the value is interpreted as a command to execute before
    the printing of each primary prompt ($PS1).

Je ne l'ai jamais utilisé, mais j'aurais pu m'en servir à l'époque où j'avais seulement sh .

53voto

Bob Points 171

La différence est que PS1 est la chaîne d'invite réelle utilisée, et PROMPT_COMMAND est une commande qui est exécutée juste avant l'invite. Si vous voulez la manière la plus simple et la plus flexible de construire un prompt, essayez ceci :

Mettez ceci dans votre .bashrc fichier :

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

Ensuite, écrivez un script (Bash, Perl ou Ruby : votre choix), et le placer dans le fichier ~/bin/bash_prompt .

Le script peut utiliser toutes les informations qu'il souhaite pour construire une invite. C'est beaucoup plus simple, IMO, parce que vous n'avez pas à apprendre le langage de substitution quelque peu baroque qui a été développé juste pour l'application PS1 variable.

Vous pourriez penser que vous pourriez faire la même chose en fixant simplement PROMPT_COMMAND directement à ~/bin/bash_prompt et la mise en place PS1 à la chaîne vide.

Au début, cela semble fonctionner, mais vous découvrez rapidement que le code de lecture s'attend à ce que PS1 doit être réglé sur l'invite réelle, et lorsque vous faites défiler l'historique en arrière, les choses se mélangent en conséquence.

Cette solution de contournement entraîne PS1 pour qu'il reflète toujours la dernière invite (puisque la fonction définit l'invite réelle de l'utilisateur). PS1 utilisée par l'instance de l'interpréteur de commandes qui l'invoque), et cela permet à la ligne de lecture et à l'historique des commandes de fonctionner correctement.

20 votes

Ne pas mettre PS1 en PROMPT_COMMAND ! Définir les variables dans PROMPT_COMMAND et les utiliser dans PS1 . Dans le cas contraire, vous perdrez la possibilité d'utiliser la fonction PS1 des séquences d'échappement comme \u ou \h . Vous devez les réinventer dans PROMPT_COMMAND . Cela pourrait être possible, mais il n'est pas possible de contourner la perte de l'accès à l'information. \[ y \] qui marquent le début et la fin des caractères non imprimables. Cela signifie que vous ne pouvez pas utiliser de couleurs sans perturber le terminal quant à la longueur de l'invite. Et cela perturbe readline lors de l'édition d'une commande générant deux lignes. A la fin, vous avez un grand désordre sur l'écran.

1 votes

@ceving Vrai cela ! On peut utiliser PROMPT_COMMAND pour changer la format de votre PS1 et obtenez le meilleur des deux mondes.

4 votes

PROMPT_COMMAND est exécuté avant l'impression PS1 . Je ne vois pas de problème pour régler PS1 de l'intérieur PROMPT_COMMAND car après PROMPT_COMMAND est terminée, l'interpréteur de commandes imprime PS1 qui a été modifié à partir de PROMPT_COMMAND (ou dans ce cas, à l'intérieur prompt_command ) ?

14voto

Cyker Points 660

De man bash :

PROMPT_COMMAND

Si elle est définie, la valeur est exécutée comme une commande avant l'émission de chaque invite primaire.

PS1

La valeur de ce paramètre est développée (voir PROMPTING ci-dessous) et utilisée comme chaîne d'invite principale. La valeur par défaut est ''. \s - \v\ $ ''.

Si vous souhaitez simplement définir la chaîne d'invite, utilisez la fonction PS1 seul est suffisant :

PS1='user \u on host \h$ '

Si vous voulez faire quelque chose d'autre juste avant d'imprimer l'invite, utilisez PROMPT_COMMAND . Par exemple, si vous voulez synchroniser les écritures en cache sur le disque, vous pouvez écrire :

PROMPT_COMMAND='sync'

1 votes

Vous pouvez également définir le titre du terminal à partir de PS1 sans avoir besoin de PROMPT_COMMAND car la séquence qui a fixé le titre peut être incluse dans PS1 enveloppé de \[ y \] .

1 votes

@dolmen Très bien. Alors, faisons autre chose, comme définir dynamiquement une variable d'environnement.

0 votes

@Cyker vous pouvez définir dynamiquement la variable d'environnement dans PS1 Mais votre exemple est trivial. PS1='$(sync)user \u on host \h$ '

3voto

Geoff Nixon Points 146

Ouais, donc pour essayer de vraiment mettre le doigt dessus :

  • PROMPT_COMMAND est un outil pratique Bash mais il n'y a, à proprement parler, rien qui ne puisse être fait en utilisant les fonctions suivantes PS1 seul, correct ?

Je veux dire, si on veut set un autre dont la portée est extérieure à l'invite : selon le shell, cette variable devra probablement être déclarée en premier lieu en dehors de l'invite. $PS1 ou (dans le pire des cas) on pourrait avoir à faire preuve de fantaisie avec quelque chose qui attend sur une FIFO avant d'appeler $PS1 (et armé à nouveau à la fin de $PS1 ) ; le \u \h peut causer quelques problèmes, en particulier si vous utilisez un regex fantaisiste ; mais autrement : on peut accomplir n'importe quoi PROMPT_COMMAND en utilisant la substitution de commande dans $PS1 (et, peut-être dans certains cas, des sous-coquilles explicites) ?

N'est-ce pas ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X