Почему переменные как $PS1 в printenv не?

Из того, что я могу сказать printenv переменные среды дисплеев, но почему я не вижу другие переменные как PS1 для настройки приглашения оболочки?

Что точно printenv вывод и почему это не берет PS1? Есть ли более всесторонняя выходная команда, которая делает больше, чем printenv?

7
задан 8 December 2017 в 02:08

2 ответа

Поэтому PS1 обычно не экспортируется.

Переменные среды используются для установки среды выполнения дочерних процессов; с тех пор PS1 только действительно имеет значение в интерактивной оболочке, обычно нет никакой точки, экспортирующей его - это - просто плоскость переменная оболочки .

при запуске интерактивного дочернего элемента оболочка , затем она считает и установит PS1 от файла ресурсов оболочки такой как ~/.bashrc

, Если Вы export PS1 затем Вы будете видеть его в эти printenv вывод. Кроме того, Вы видите простые переменные оболочки с помощью удара, встроенного set, как описано здесь , Как перечислить все имена переменных и их текущие значения?

6
ответ дан 23 November 2019 в 06:26

Есть ли более всесторонняя выходная команда, которая делает больше, чем printenv?

printenv печать только переменные среды, которые можно считать преимуществом. Но если Вы хотите распечатать переменные оболочки также, использовать echo "$x" (или printf '%s\n' "$x", который более устойчив) вместо printenv x.

объяснение steeldriver этих проблем полезно и корректно, но я представляю тему в другом отношении здесь.

printenv внешняя команда - не встроенный в Вашу оболочку, но отдельную программу от Вашей оболочки. Это показывает свои собственные переменные среды, которые являются теми, которые это наследовало от оболочки, которую Вы используете для выполнения его. Однако оболочки не передают все свои переменные в среды их подпроцессов. Вместо этого они поддерживают различие, между которым переменные являются переменными среды и которые не являются. (Те, которые не являются, часто являются переменными оболочки вызова.)


Переменные Shell

Чтобы видеть, как это работает, попробуйте эти команды, в которые включают ( ) таким образом, они действуют independently1 друг друга. Индивидуально, каждая из этих команд работает то же при выполнении его без ( ), но переменные, которые Вы создаете в более ранних командах, все еще существовали бы в более поздних командах. Выполнение команд в подоболочках предотвращает это.

Создание новой переменной, затем выполнение внешней команды, не передают переменную в среду команды. Кроме необычного случая, что у Вас уже есть переменная среды x, эта команда не производит вывода:

(x=foo; printenv x)

Переменная присвоена в оболочке, все же. Эта команда выводы foo:

(x=foo; echo "$x")

Оболочка поддерживает синтаксис для передачи переменной в среду команды, не влияя на среду текущей оболочки. Это производит foo:

x=foo printenv x

(Который работает в подоболочке также, конечно-(x=foo printenv x)- но я показал его без ( ) потому что при использовании того синтаксиса ничто не установлено для текущей оболочки, так использование подоболочки является ненужным, чтобы препятствовать тому, чтобы были затронуты последующие команды.)

Это печатает foo, затем печать bar:

(x=bar; x=foo printenv x; echo "$x")

Экспорт

При экспорте переменной она автоматически передается в среды всех последующих внешних команд, выполненных от той же оболочки. export команда делает это. Можно использовать его перед определением переменной после определения его, или можно даже определить переменную в export управляйте собой. Все они печатают foo:

(x=foo; export x; printenv x)
(export x; x=foo; printenv x)
(export x=foo; printenv x)

Существует нет unexport команда. Даже при том, что можно экспортировать переменную прежде, чем установить его, сбрасывание переменной также не экспортирует его, который должен сказать, что это ничего не печатает вместо печати bar:

(x=foo; export x; unset x; x=bar; printenv x)

Но изменение значения переменной после экспорта его действительно влияет на экспортируемое значение. Это печатает foo, затем bar:

(export x=foo; printenv x; x=bar; printenv x)

Как другие процессы, Ваша оболочка сама наследовала переменные среды от своего родительского процесса. Такие переменные присутствуют первоначально в среде Вашей оболочки, и они автоматически экспортируются - или остаются экспортируемыми, если Вы принимаете решение думать о ней тот путь. Это печатает foo (помните, VAR=val cmd выполнения cmd с VAR набор к val в его среде):

x=foo bash -c 'printenv x'

Набор переменных в дочерних процессах не влияет на родительский процесс, даже если они экспортируются. Это печатает foo (нет bar):

(x=foo; bash -c 'export x=bar'; echo "$x")

Подоболочки

Подоболочка является также дочерним process2; это также печатает foo:

(x=foo; (export x=bar); echo "$x")

Это должно сделать более ясным, почему я включил большинство этих команд в ( ) выполнять их в подоболочках.

Подоболочки являются особенными, все же. В отличие от других подпроцессов, таких как созданные, когда Вы выполняете внешнюю команду как printenv или bash, подоболочка наследовала большую часть состояния своей родительской оболочки. В частности, подоболочки наследовали даже переменные, которые не экспортируются. Так же, как (x=foo; echo "$x") печать foo, делает (x=foo; (echo "$x")).

Неэкспортируемая переменная все еще не экспортируется в подоболочке - если Вы не экспортируете ее - так, так же, как (x=foo; printenv x) печать ничто, делает (x=foo; (printenv x)).

Подоболочка является специальным видом подпроцесса, который является оболочкой. Не все подпроцессы, которые являются оболочками, являются подоболочками. Оболочка создается путем выполнения bash не подоболочка, и она не наследовала неэкспортируемые переменные. Таким образом, эта команда печатает пустую строку (потому что echo печатает новую строку, даже когда названо с пустым аргументом):

(x=foo; bash -c 'echo "$x"')

Почему PS1 не переменная среды (и обычно не должен быть один),

Наконец, что касается почему быстрые переменные как PS1 переменные оболочки, но не переменные среды, причины:

  1. Они только необходимы в оболочке, не других программах.
  2. Они установлены для каждой интерактивной оболочки, и неинтерактивным оболочкам не нужны они вообще. Таким образом, они не должны быть наследованы.
  3. Попытка передать PS1 к новой оболочке обычно перестал бы работать, потому что оболочка обычно сбрасывает PS1.

Точка № 3 заслуживает немного большего количества объяснения, хотя, если Вы никогда не пытаетесь сделать PS1 переменная среды, затем Вы, вероятно, не должны действительно знать детали.

Когда Bash запускается нев интерактивном режиме, он сбрасывает PS1.

Когда неинтерактивная оболочка Bash запускает, это сбросы always3 PS1. Это печатает пустую строку (нет foo):

PS1=foo bash -c 'echo "$PS1"'

Чтобы проверить, что это на самом деле сброшено, и не только набор, но и пустое, можно выполнить это, которое печатает unset:

PS1=foo bash -c 'if [[ -v PS1 ]]; then echo set; else echo unset; fi'

Чтобы проверить, что это независимо от другого поведения запуска, Вы могли попытаться передать любую комбинацию --login, --norc, или --posix прежде -c, или установка BASH_ENV к пути некоторого сценария (например, BASH_ENV=~/.bashrc PS1=foo bash ...), или ENV если Вы передали --posix. Ни в коем случае не делает неинтерактивный сбой оболочки Bash для сбрасывания PS1.

То, что это означает, является этим, если Вы экспортируете PS1 и выполненный неинтерактивная оболочка, которая сама выполняет интерактивную оболочку, которую она не установит, имеет PS1 оцените Вы первоначально устанавливаете. Поэтому - и также потому что другие оболочки помимо Bash (как Ksh) все не ведут себя тот же путь и способ, которым Вы пишете PS1 поскольку Bash не всегда работает на те оболочки - я рекомендую против попытки сделать PS1 переменная среды. Просто редактирование ~/.bashrc для установки безотносительно подсказки, Вы хотите.

Когда Bash запускается в интерактивном режиме, он часто устанавливает или сбрасывает PS1.

С другой стороны, если Вы сбрасываете PS1 и выполненный интерактивная оболочка Bash, даже если Вы препятствуете тому, чтобы он выполнил команды из сценариев запуска путем передачи --norc, это все еще автоматически установит PS1 к значению по умолчанию. Выполнение env -u PS1 bash --norc дает Вам интерактивную оболочку Bash с PS1 набор к \s-\v\$ . Так как Bash расширяется \s к названию оболочки и \v к номеру версии это показывает bash-4.3$ как подсказка на Ubuntu 16.04 LTS. Отметьте ту установку PS1оцените, поскольку пустая строка не является тем же как сбрасыванием его. Как объяснено ниже, работая PS1= bash дает Вам интерактивную оболочку со странным поведением запуска. Необходимо постараться не экспортировать PS1 когда это установлено на пустую строку в практическом применении, если Вы не понимаете и хотите то поведение.

Однако, если Вы устанавливаете PS1 и выполненный интерактивная оболочка Bash - и это не становится сброшенным посреднической неинтерактивной оболочкой - это сохранит то значение... до сценария запуска как глобальное /etc/profile (для оболочек входа в систему) или /etc/bash.bashrc, или Ваше в расчете на пользователя ~/.profile, ~/.bash_login, или ~/.bash_profile (все для оболочек входа в систему) или ~/.bashrc сброс это.

Даже если Вы редактируете те файлы, чтобы препятствовать тому, чтобы они установили PS1- который, в случае /etc/profile и /etc/bash.bashrc, Я рекомендую против выполнения так или иначе, так как они влияют на всех пользователей - Вы не можете действительно полагаться на это. Как упомянуто выше, интерактивные оболочки, запущенные с неинтерактивных оболочек, не будут иметь PS1, если Вы не должны были сбрасывать и реэкспортировать его в неинтерактивной оболочке. Кроме того, необходимо думать дважды прежде, чем сделать это, потому что это характерно для кода оболочки (включая функции оболочки, которые Вы, возможно, определили) проверять PS1 определить, работает ли оболочка это в, является интерактивным или неинтерактивным.

Проверка PS1 распространенный способ состоит в том, чтобы определить, является ли текущая оболочка интерактивной.

Поэтому для неинтерактивного Bash shells4 настолько важно сбросить PS1 автоматически. Как разделяют 6.3.2, этот Интерактивный Shell? из Bash говорится в справочнике:

[S] сценарии tartup могут исследовать переменную PS1; это сброшено в неинтерактивных оболочках и установлено в интерактивных оболочках.

Чтобы видеть, как это работает, посмотрите пример там. Или проверьте реальное использование в Ubuntu. По умолчанию, /etc/profile в Ubuntu включает:

if [ "$PS1" ]; then
  if [ "$BASH" ] && [ "$BASH" != "/bin/sh" ]; then
    # The file bash.bashrc already sets the default PS1.
    # PS1='\h:\w\$ '
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
  else
    if [ "`id -u`" -eq 0 ]; then
      PS1='# '
    else
      PS1='$ '
    fi
  fi
fi

/etc/bash.bashrc, то, которое не должно делать ничего вообще, когда оболочка является неинтерактивной, имеет:

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

Тонкость различных методов проверки интерактивность:

Достигнуть той же цели, /etc/skel/.bashrc, который копируется в корневые каталоги пользователей, когда их учетные записи создаются (так Ваш ~/.bashrc вероятно, подобно), имеет:

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

Это - другой распространенный способ проверить, является ли оболочка интерактивной: посмотрите если текст, полученный путем расширения специального параметра - (путем записи $-) содержит букву i. Обычно это имеет точно тот же эффект. Предположим, однако, что Вы не изменили код, показанный выше этого, появляется по умолчанию в сценариях запуска Bash в Ubuntu, и что:

  1. Вы экспортируете PS1 как переменная среды, и
  2. это установлено, но к пустому значению, и
  3. Вы запускаете интерактивную оболочку Bash...

Затем /etc/profile (если это - оболочка входа в систему), или /etc/bash.bashrc не выполнит команды, которые они обычно выполняют для интерактивных оболочек. ~/.bashrc все еще будет.

Если Вы хотите проверить, является ли оболочка интерактивной при помощи PS1 и получите правильный ответ даже когда PS1 установлен, но пуст, можно использовать [[ -v PS1 ]] или [ -v PS1 ]/test -v PS1 вместо этого. Обратите внимание, однако, что [[ ключевое слово, и -v тест [ и test окружите builtins, конкретны к Bash. Не все другие оболочки стиля Границы принимают их. Таким образом, Вы не должны использовать их в сценариях как ~/.profile и /etc/profile это могло бы работать в других оболочках (или менеджером по оформлению, когда Вы входите в систему графически), если у Вас нет чего-то еще в сценарии, который проверяет, какая оболочка выполняет и только выполняет определенные для Bash команды, когда та оболочка является Bash (например, путем проверки $BASH_VERSION).


Примечания

1 Эта статья объясняет подоболочки подробно. 3.2.4.3 Группировка Команд справочника Bash объясняет ( ) синтаксис.

2 Примечания, что существуют обстоятельства под который команды, выполненные в подоболочках даже с ( ) синтаксис не используется. Например, когда у Вас есть команды, разделенные | в конвейере Bash выполняет каждого из них в подоболочке (если lastpipe опция оболочки установлена).

3 За исключением подоболочек. Возможно это даже не исключение, так как подоболочки не "запускают" в обычном смысле, который мы имеем в виду, когда мы говорим об этом. (У них действительно нет значительного поведения инициализации.) Отмечают это, когда Вы работаете bash- с или без аргументов - в оболочке Bash, которая создает подпроцесс, который является оболочкой, но это не подоболочка.

4 Примечания, что не все оболочки - даже все оболочки стиля Границы - ведут себя этот путь. Но Bash делает, и коду Bash, включая код в сценариях запуска, очень свойственно полагаться на него.

4
ответ дан 23 November 2019 в 06:26

Другие вопросы по тегам:

Похожие вопросы: