Яка різниця між PS1 та PROMPT_COMMAND


108

Оглядаючи цю дивовижну нитку я помітив, що деякі приклади використовують

PS1="Blah Blah Blah"

а деякі використовують

PROMPT_COMMAND="Blah Blah Blah"

(а деякі використовують і те і інше) під час встановлення підказки в оболонці bash. Яка різниця між ними? Пошук ТА та навіть трохи ширший пошук у Google не дають мені результатів, тому навіть посилання на потрібне місце для пошуку відповіді буде оцінено.

Відповіді:



67

PROMPT_COMMAND може містити звичайні оператори bash, тоді як змінна PS1 також може містити в змінній спеціальні символи, такі як "\ h" для імені хоста.

Наприклад, ось мій баш-рядок, який використовує як PROMPT_COMMAND, так і PS1. Код bash в PROMPT_COMMAND визначає, в якій гітці git ви можете знаходитись, і відображає це під час запиту, а також статус виходу останнього процесу запуску, ім'я хоста та базове ім'я pwd. Змінна RET зберігає повернене значення останньої виконаної програми. Це зручно, щоб побачити, чи була помилка та код помилки останньої програми, яку я запустив у терміналі. Зверніть увагу на зовнішнє ", що оточує весь вираз PROMPT_COMMAND. Він включає PS1, так що ця змінна переоцінюється щоразу, коли змінна PROMPT_COMMAND оцінюється.

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";'

Приклад виводу виглядає так у каталозі, що не містить git:

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

і в каталозі git ви бачите назву гілки:

sashan@dhcp-au-122 rework mybranch $ 

Оновлення

Прочитавши коментарі та відповідь Боба, я думаю, що краще писати його так, як він описує. Це більш рентабельне, ніж те, що я спочатку писав вище, де змінна PS1 встановлюється всередині PROMPT_COMMAND, що сама по собі є надто складною рядком, що оцінюється під час виконання за допомогою bash. Це працює, але це складніше, ніж потрібно. Чесно кажучи, я написав, що PROMPT_COMMAND для себе близько 10 років тому, і він працював і не надто думав про це.

Для тих, хто цікавиться, як я змінив свої речі, я в основному поклав код для PROMPT_COMMAND в окремий файл (як описав Боб), а потім повторює рядок, який я маю намір 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"

і в моєму .bashrc

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

1
Ви могли б скоротити одну з ваших ліній: if git branch &>/dev/null ; then\ . Він перенаправляє як stdout, так і stderr на / dev / null. tldp.org/LDP/abs/html/io-redirection.html

3
Не потрібно експортувати PROMPT_COMMAND .
долмен

2
Я думаю, що коментар Цевінга дуже відповідає і цій відповіді:Don't set PS1 in PROMPT_COMMAND! Set variables in PROMPT_COMMAND and use them in PS1
phil294

2
Я не бачу причини, чому зміна в PS1Інтернеті всередині PROMPT_COMMANDє невигідним. Це ідеальний корисний код. На відміну від відповіді Боба вниз, PS1змінна була правильно побудована. Це дозволяє значно вдосконалити підказку на баш, залежно від вашої реальної ситуації.
Крістіан Вольф

2
@ChristianWolf будівництво PS1всередині PROMPT_COMMANDне виконує жодних цілей. це приклад, як цього не зробити. побудуйте PS1один раз .bash_profile, просто використовуйте одиничні лапки замість подвійних лапок, так що змінні підстановки будуть оцінені під час кожного запиту.
товариш

46

Різниця полягає в тому, що PS1 - це фактично використовуваний рядок підказки, а PROMPT_COMMAND - команда, яка виконується безпосередньо перед підказкою. Якщо ви хочете найпростіший, гнучкіший спосіб побудови підказки, спробуйте це:

Помістіть це у свій .bashrc:

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

Потім напишіть сценарій (bash, perl, ruby: ваш вибір) та помістіть його у ~ / bin / bash_prompt.

Сценарій може використовувати будь-яку інформацію, що йому подобається, щоб побудувати підказку. Це набагато простіше IMO, оскільки вам не доведеться вивчати дещо барокову мову заміни, розроблену саме для змінної PS1.

Ви можете подумати, що ви можете зробити те саме, просто встановивши PROMPT_COMMAND безпосередньо в ~ / bin / bash_prompt і встановивши PS1 на порожній рядок. Спочатку, здається, це спрацює, але незабаром ви виявите, що код перегляду очікує, що PS1 буде встановлений у фактичному запиті, і коли ви прокручуєте в історії історію, в результаті речі заплутуються. Таке вирішення призводить до того, що PS1 завжди відображає останню підказку (оскільки функція встановлює фактичний PS1, використаний викликаючим екземпляром оболонки), і це змушує нормально працювати лінії читання та історії команд.


17
Не встановлюйте PS1в PROMPT_COMMAND! Встановити змінні в PROMPT_COMMANDі використовувати їх у PS1. В іншому випадку ви втратите можливість використовувати PS1послідовності втечі, як \uабо \h. Ви повинні їх винаходити знову PROMPT_COMMAND. Це може бути можливо , але це не можливо працювати навколо втрачати з \[і \]які відзначають початок і кінець , які не є друкованих символів. Це означає, що ви не можете використовувати кольори, не плутаючи термінал щодо довжини підказки. І це плутається readlineпід час редагування команди, що породжує два рядки. Зрештою, у вас великий безлад на екрані.
закінчення

1
@ceving Це правда! Можна скористатися PROMPT_COMMAND, щоб змінити формат PS1 і отримати найкраще з обох світів
2grit

3
PROMPT_COMMANDвиконується перед друком PS1. Я не бачу проблем із налаштуванням PS1зсередини PROMPT_COMMAND, тому що після PROMPT_COMMANDзакінчення буде надруковано оболонку PS1, яку було змінено PROMPT_COMMAND(або в цьому випадку всередині prompt_command)?
Феліпе Альварес

3
Попередження: PROMPT_COMMAND, як правило, не слід використовувати для друку символів безпосередньо в підказку. Символи, надруковані поза PS1, Bash не враховують, що призведе до неправильного розміщення курсору та очищення символів. Або використовуйте PROMPT_COMMAND для встановлення PS1 або дивіться на вбудовування команд. ( Arch Wiki Source )
meffect

3
я не розумію, чому всі намагаються робити якісь хитрощі в PROMPT_COMMAND замість того, щоб просто використовувати підстановку команд у PS1, export PS1='$(~/bin/bash_prompt)'це те саме, що помилка виглядає розумним
товариш

10

Від man bash:

PROMPT_COMMAND

Якщо встановлено, значення виконується як команда перед видачею кожного первинного запиту.

PS1

Значення цього параметра розширюється (див. ЗАПРОШЕННЯ нижче) і використовується як основний рядок підказок. Значенням за замовчуванням є '' \ s- \ v \ $ ''.

Якщо ви просто хочете встановити рядок підказок, PS1достатньо використовувати тільки:

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

Якщо ви хочете зробити щось інше безпосередньо перед друком підказки, використовуйте PROMPT_COMMAND. Наприклад, якщо ви хочете синхронізувати кешоване записування на диск, ви можете написати:

PROMPT_COMMAND='sync'

1
Ви також можете встановити заголовок терміналу PS1без необхідності PROMPT_COMMAND, оскільки послідовність, що встановлює заголовок, може бути включена в PS1загорнуте з \[і \].
долмен

1
@dolmen Гаразд. Тоді давайте зробимо щось інше, наприклад динамічне встановлення змінної середовища.
Cyker

@Cyker ви можете динамічно встановити змінну середовища в PS1, вона просто буде встановлена ​​в нижній частині, тому ви не зможете повернути її значення. але ваш приклад банальнийPS1='$(sync)user \u on host \h$ '
товариш

1

різниця в тому

  • якщо ви виведете неповний рядок PROMPT_COMMAND, він накрутить ваш bash-підказку
  • PS1 замінники \H та друзі
  • PROMPT_COMMANDзапускає його вміст, PS1використовує його вміст як підказку.

PS1робить змінне розширення та заміну команд у кожному запиті, не потрібно використовувати PROMPT_COMMANDдля призначення значення PS1або запускати довільний код. ви можете легко зробити export PS1='$(uuidgen) $RANDOM'один раз .bash_profile, просто використовуйте одинарні лапки


0

Так, щоб спробувати по-справжньому прибити це:

  • PROMPT_COMMAND- це зручна змінна / функція bash , але, строго кажучи, нічого, що також не можна зробити, використовуючи PS1самостійно, правильно?

Я маю на увазі, якщо потрібно встановити іншу змінну з областю поза підказкою: залежно від оболонки, цю змінну, мабуть, потрібно буде оголосити першою зовні $PS1або (в гіршому випадку), можливо, доведеться пофантазувати на те, що чекає на FIFO до дзвінок$PS1 (і знову озброєний в кінці $PS1); це \u \hможе спричинити певні неприємності, особливо якщо ви використовуєте якийсь фантазійний регулярний вираз; але в іншому випадку: можна зробити все, що завгодно PROMPT_COMMAND, використовуючи підстановку команд всередині $PS1(а, може, у кутових випадках, явних підшах)?

Правильно?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.