Призначення [-n “$ PS1”] в bashrc


10

Яка мета робить [ -n "$PS1" ]в [ -n "$PS1" ] && source ~/.bash_profile;служите? Цей рядок входить .bashrcдо репототу точкових файлів .

Відповіді:


20

Це перевірка, чи оболонка інтерактивна чи ні. У цьому випадку ~/.bash_profileфайл можна розміщувати лише в тому випадку, якщо оболонка інтерактивна.

Дивіться "Чи інтерактивна ця оболонка?" у посібнику з bash, де цитується ця конкретна ідіома. (Також рекомендується перевірити, чи оболонка є інтерактивною, перевіривши, чи $-містить спеціальна змінна iсимвол, що є кращим підходом до цієї проблеми.)


Баш, принаймні, буде скинутим PS1 та PS2, якщо оболонка інтерактивна . Ви можете бачити це для себе, за допомогою ( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )якого просто друкується []. Здається, zsh не робить те саме, принаймні з експерименту ... У будь-якому випадку, намір[ -n "$PS1" ] полягає в тому, щоб перевірити, чи оболонка є інтерактивною чи ні.
filbranden

3
Це bashзнімає PS1, коли неінтерактивна (помилка в попередньому коментарі) є помилкою IMO, PS1 не є специфічною для змінного струму змінною. Це єдина оболонка, яка робить це (хоча yashтакож встановлює PS1значення за замовчуванням, навіть коли не є інтерактивним).
Стефан Шазелас

1
Оскільки відповідний код знаходиться у файлі, що стосується bash, це здається розумною відповіддю. Інші відповіді стосуються більш загального випадку специфікацій POSIX або інших оболонок. Ви відповіли на те, "яка мета цього?" Намір у питанні, а належним чином залишаючи осторонь решту. Добре знати, що робить баш і, можливо, кращі способи досягнення мети.
Jeff Schaller

Я вважаю цю відповідь більш повною, якби вона запропонувала більш надійну альтернативу (скажімо, [[ $- = *i* ]] && source ~/.bash_profile).
Чарльз Даффі

@CharlesDuffy Чесно кажучи, я не думаю, що в цьому багато не так [ -n "${PS1}" ], але я все-таки оновив свою відповідь, щоб підкреслити, що посібник з bash також пропонує / рекомендує перевірити, $-щоб визначити, чи оболонка є інтерактивною, я сподіваюся, ви знайдете, що покращує відповідь. Ура!
filbranden

19

Що це робить

Це широко розповсюджений спосіб перевірити, чи інтерактивна оболонка. Слідкуйте за тим, щоб він працював лише в баш, він не працює з іншими оболонками. Так що це нормально (якщо нерозумно) для .bashrc, але він би не працював .profile(що читається sh, а bash - лише одна з можливих реалізацій sh, а не найпоширеніша).

Чому це працює (тільки в баш!)

Інтерактивна оболонка встановлює змінну оболонкиPS1 на рядок підказок за замовчуванням. Отже, якщо оболонка інтерактивна, PS1встановлюється (якщо тільки користувач її .bashrcне видалив, що ще не могло статися вгорі .bashrc, і ви можете вважати, що це все-таки дурне).

Зворотне і в bash: неінтерактивні екземпляри bash unset PS1під час їх запуску. Зауважте, що така поведінка характерна для bash, і, ймовірно, помилка (чому б bash -c '… do stuff with $var…'не працювати, коли varє PS1?). Але всі версії bash аж до 4.4 (включаючи останню версію, як я пишу) роблять це.

Багато систем експортують PS1у навколишнє середовище. Це погана ідея, оскільки багато різних оболонок використовують, PS1але з іншим синтаксисом (наприклад , швидкі втечі башів повністю відрізняються від швидких втечі zsh ). Але це досить поширено, що на практиці бачення PS1встановленого не є надійним показником того, що оболонка є інтерактивною. Оболонка, можливо, успадкувала PS1від навколишнього середовища.

Чому це (помилково) використовується тут

.bashrcце файл, який баш читає при запуску, коли він інтерактивний. Менш відомий факт полягає в тому, що bash також читає .bashrcоболонку входу, і евристика bash робить висновок, що це віддалений сеанс (bash перевіряє, чи є його батьківський rshdабо sshd). У цьому другому випадку навряд чи це PS1було б встановлено в оточенні, оскільки ще не запущено жодного файлу точок.

Однак спосіб використання кодом цієї інформації контрпродуктивний.

  • Якщо оболонка - це інтерактивна оболонка, то вона працює .bash_profileв цій оболонці. Але .bash_profileце сценарій часу входу. Він може запускати деякі програми, які призначені для запуску лише один раз за сеанс. Це може змінити деякі змінні середовища, які користувач навмисно встановив на інше значення перед запуском оболонки. Запуск .bash_profileу оболонці без входу є руйнівним.
  • Якщо оболонка - неінтерактивна оболонка віддаленого входу, вона не завантажується .bash_profile. Але це той випадок, коли завантаження .bash_profileможе бути корисним, оскільки неінтерактивна оболонка входу не завантажується автоматично /etc/profileі ~/.profile.

Я думаю, що люди це роблять в тому, що користувачі, які входять у систему через графічний інтерфейс (дуже поширений випадок) і .bash_profileзамість того, щоб замінити їх налаштування змінної середовища .profile. Більшість механізмів входу в графічний інтерфейс викликають, .profileале не .bash_profile(для читання .bash_profileпотрібен запуск bash як частина запуску сеансу, а не sh). При такій конфігурації, коли користувач відкриє термінал, він отримає свої змінні середовища. Однак користувач не отримає своїх змінних оточуючих середовищ у додатках GUI, що є дуже поширеним джерелом плутанини. Рішення тут полягає у використанні .profileзамість .bash_profileвстановлення змінних середовища. Додавання мосту між собою .bashrcі .bash_profileстворює більше проблем, ніж вирішує.

Що робити замість цього

Існує простий, портативний спосіб перевірити, чи інтерактивна оболонка поточна: перевірити, чи -iвключена опція .

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This shell is not interactive";;
esac

Це корисно .bashrcдля читання, .profileлише якщо оболонка не інтерактивна, тобто навпаки, що робить код! Прочитайте, .profileчи є bash (неінтерактивна) оболонка для входу, і не читайте її, якщо це інтерактивна оболонка.

if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi

4
Можливо, варто відзначити, що кращий спосіб перевірити, чи оболонка інтерактивна - це [[ -o interactive ]](ksh, bash, zsh) або case $- in (*i*) ...; esac(POSIX)
Stéphane Chazelas

2
Мій bash (версія 4.4.12) насправді, здається, PS1не працює, якщо не працювати інтерактивно. Тестувати досить просто: PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'нічого не надрукує, при цьому PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'надрукує значення, $PS1встановлене у ваших файлах запуску bash (він не буде друкувати рядок "зозуля").
FooF

1
@ Stéphane Chazelas: POSIX не вимагає, $-містить iз інтерактивною оболонкою.
шилі

1
Bosh робить це з 2012 року, щоб бути сумісним ksh. Просто POSIX не вимагав, поки зміна, яку ви запропонували, не набуде чинності.
schily

1
Щиро кажучи, я б сказав, що називати [ -n "${PS1}" ] неправильним є занадто далеко, адже він порушується лише тоді, коли хтось експортує PS1 (що у вашій відповіді ви говорите, що це погана ідея і навіть вникати в причини), і це не впливає все-таки бійся (оскільки він знімає PS1 і PS2, якщо оболонка не інтерактивна.) Можливо, використовувати таке слово, як "відсторонений" або говорити про "обмеження" підходу було б краще. Я взагалі не думаю, що це "неправильно". Якщо щось не так - експорт PS1, це точно! У будь-якому випадку, дякую за детальну інформацію про це.
filbranden

1

Здається, що ця дивна концепція є результатом того, що bashвін починався не як клон оболонки POSIX, а як Bourne Shellклон.

Як результат, інтерактивна поведінка POSIX ( $ENVвикликається інтерактивними оболонками) була додана пізніше bashі широко не відома.

Є одна оболонка, яка надає подібну поведінку. Це cshі csh гранти, які $promptмають конкретні значення:

$prompt not set          non-interactive shell, test $?prompt.
$prompt set but == ""    .cshrc called by the which(1) command.
$prompt set and != ""    normal interactive shell.

Але це не стосується ні оболонки Борна, ні снарядів POSIX.

Для оболонки POSIX єдиним наданим методом є введення коду для інтерактивних оболонок у файл:

$ENV

що має конкретну назву оболонки. Це напр

$HOME/.kshrc    for the korn shell
$HOME/.bashrc   for bash
$HOME/.mkshrc   for mksh
$HOME/.shrc     for the POSIX Bourne Shell

Інші люди згадували прапор оболонки -i, але це не підходить для надійного програмування. POSIX не вимагає, щоб це set -iпрацювало, і не $-містить iінтерактивних оболонок. POSIX вимагає просто sh -iввести оболонку в інтерактивний режим.

Оскільки змінна $PS1може бути імпортована із середовища, вона може мати значення навіть у неінтерактивному режимі. Те, що bash unsets PS1у будь-якій неінтерактивній оболонці не надається стандартом і не робиться жодною іншою оболонкою.

Таким чистим програмуванням (навіть з bash) є введення команд для інтерактивних оболонок $HOME/.bashrc.


0

Я збираюся спочатку поговорити про те, що Debian, і більшість часу також Ubuntu встановлює для bash. І останні торкаються інших систем.

В налаштуваннях файлів запуску оболонки існує думка.
Я також маю свою думку, але спробую показати наявні приклади правильних налаштувань.
Я буду використовувати debuan, оскільки досить легко знайти приклади його файлів.
І Debian широко використовується, тому налаштування добре перевірені,

Яка мета перевірити, чи встановлено PS1?

Тільки щоб з’ясувати, чи оболонка інтерактивна.

За замовчуванням /etc/profileу debian та ubuntu (з / usr / share / base-files / profile):

if [ "${PS1-}" ]; then
    if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then

Якщо читається: якщо інтерактивна (встановлено стандарт PS1 за замовчуванням), і це оболонка bash (але не діє як за замовчуванням sh), тоді змініть PS1 на конкретну нову (не за замовчуванням).

За замовчуванням /etc/bash.bashrcу debian також міститься:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Що досить ясно в тому, що він робить: Якщо інтерактивний не вказує джерело (решта).

Однак, в /etc/skel/.bashrcє прикладом правильного способу тестування на інтерактивну оболонку (за допомогою $-):

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Це повинно чітко показати, чому саме PS1 та одна альтернатива.

Правильний порядок

Налаштування, про яке ви повідомляєте, слід уникати.
Порядок (від системних налаштувань і більш конкретних налаштувань (для Баш)) є /etc/profile, /etc/bash.bashrc, ~/.profileі , нарешті ~/.bashrc. Це дає найбільш широкі ефекти (і для більшої кількості оболонок) у /etc/profile(який належить корінь), а далі /etc/bash.bashrc(який також належить корінь), але впливає лише на bash. Тоді з’являються особисті налаштування $HOME, перший - ~/.profileдля більшості оболонок і ~/.bashrc(майже еквівалентний ~/.bash_profile), специфічний лише для баш.

Тому неправильно джерело ~/.bashrcв ~/.profileце трансформує специфічний для установки Баша до більш загальним , що користувачеві зачіпають більш оболонки . За винятком випадків, коли це зроблено таким чином :

# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

Він перевіряє, що bash працює і завантажується лише .bashrcв тому випадку.

Це рішення, що надходить від Debian. Обґрунтування пояснюється тут .

Насправді, зворотний зв'язок ~/.profileу ~/.bash_profile(або ~/.bashrc) є лише повторним застосуванням загальних правил, які повинні були бути завантажені вже до певного випадку використання, а отже, «не так погано» (я не кажу «добре»). І я не кажу, що це добре, тому що це може призвести до отримання циклу пошуку файлів. Як і коли підкаталог завантажує батьків, тобто цикл каталогів.

І чи є в цьому перехресне джерело, що перевірка на інтерактивну оболонку має сенс. Тільки коли інтерактивна оболонка ~/.bashrcзавантажується, але вона, в свою чергу, може завантажуватися ~/.profile(або навпаки), і в цьому випадку може бути використана перевірка інтерактивної оболонки.

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