web-dev-qa-db-fra.com

Quelle est la différence entre PS1 et Prompt_COMMAND

En regardant ce fil 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) lors du réglage de l'invite dans un shell bash. Quelle est la différence entre les deux? Une recherche SO et même un peu de recherche google plus large ne m'obtiennent pas de résultats, alors même un lien vers le bon endroit pour chercher la réponse serait apprécié.

90
Jed Daniels

Depuis la page du document GNU Bash: http://www.gnu.org/software/bash/manual/bashref.html

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 l'utiliser à l'époque où je n'avais que sh.

48
Scott Thomson

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

Par exemple, voici mon invite bash qui utilise 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 le statut de sortie du dernier processus exécuté, le nom d’hôte et le nom de base du mot de passe. La variable RET stocke la valeur de retour du dernier programme exécuté. C'est pratique pour voir s'il y a une erreur et le code d'erreur du dernier programme que j'ai exécuté dans le terminal. Notez le 'entourant l'expression entière Prompt_COMMAND. Il inclut PS1 pour 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 $ 

Mettre à jour

Après avoir lu les commentaires et la réponse de Bob, je pense que l'écrire comme il le décrit est préférable. Il est plus facile à gérer que ce que j'avais initialement écrit ci-dessus, où la variable PS1 est définie dans Prompt_COMMAND, qui est une chaîne extrêmement compliquée qui est évaluée à l'exécution par bash. Cela fonctionne, mais c'est plus compliqué que nécessaire. Pour être juste, j’ai écrit Prompt_COMMAND pour moi-même il ya environ 10 ans et cela a fonctionné et n’y a pas trop réfléchi.

Pour ceux qui sont curieux de savoir comment j'ai modifié mes modifications, j'ai essentiellement mis le code de Prompt_COMMAND dans un fichier séparé (comme Bob l'a décrit), puis répercuté la chaîne que j'ai l'intention d'ê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

function Prompt_command {
    RET=$?
    export PS1=$(~/.bash_Prompt_command $RET)
}
Prompt_DIRTRIM=3
export Prompt_COMMAND=Prompt_command
57
sashang

La différence est que PS1 est la chaîne d'invite réellement utilisée et Prompt_COMMAND, une commande exécutée juste avant l'invite. Si vous voulez le moyen le plus simple et le plus flexible de créer une invite, essayez ceci:

Mettez ceci dans votre .bashrc:

function Prompt_command {
  export PS1=$(~/bin/bash_Prompt)
}
export Prompt_COMMAND=Prompt_command

Ensuite, écrivez un script (bash, Perl, Ruby: votre choix) et placez-le dans ~/bin/bash_Prompt.

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

Vous pourriez penser que vous pourriez faire la même chose en définissant simplement Prompt_COMMAND directement sur ~/bin/bash_Prompt et en définissant PS1 sur la chaîne vide. Au début, cela semble fonctionner, mais vous découvrez rapidement que le code de la readline s'attend à ce que PS1 soit défini sur l'invite réelle et, lorsque vous faites défiler les mots clés de l'historique, tout est gâché. Cette solution de contournement fait en sorte que PS1 reflète toujours la dernière invite (car la fonction définit la valeur PS1 réelle utilisée par l'instance invoquante du shell), ce qui facilite le fonctionnement de l'historique de lecture et de commande.

40
Bob

De man bash :

Prompt_COMMAND

Si elle est définie, la valeur est exécutée en tant que commande avant l'émission de chaque invite principale. 

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 voulez simplement définir la chaîne d'invite, utiliser PS1 seul est suffisant:

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

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

Prompt_COMMAND='sync'
8
Cyker

Oui, alors essayez vraiment de bien comprendre:

  • Prompt_COMMAND est une pratique bash commodité/fonction pratique, mais il n’ya rien à proprement parler qui ne puisse également être utilisé avec PS1 seul, correct?

Je veux dire, si on veut définir une autre variable avec une étendue en dehors de l'invite: selon le shell, cette variable devra probablement être déclarée première en dehors de $PS1 ou (pire des cas), avoir envie de quelque chose en attente d'un FIFO avant d'appeler $PS1 (et de se réarmer à la fin de $PS1); le \u\h peut causer des problèmes, surtout si vous utilisez des expressions rationnelles sophistiquées; mais sinon: on peut accomplir tout ce que Prompt_COMMAND peut faire en utilisant la substitution de commande dans $PS1 (et, éventuellement, dans certains cas, des sous-shell explicites)?

Droite?

0
Geoff Nixon

la différence est que 

  • si vous affichez une ligne incomplète à partir de Prompt_COMMAND, cela affichera votre invite bash
  • PS1 remplace \H et ses amis
  • Prompt_COMMAND exécute son contenu, PS1 utilise son contenu comme invite.

PS1 effectue une expansion de variable et une substitution de commande à chaque invite. Il n'est donc pas nécessaire d'utiliser Prompt_COMMAND pour attribuer une valeur à PS1 ou pour exécuter du code arbitraire. vous pouvez facilement faire export PS1='$(uuidgen) $RANDOM' une fois dans .bash_profile, utilisez simplement des guillemets simples

0
pal