Переменные среды и позиционные параметры
Прежде чем мы начнем обсуждать $INTEGER
тип переменных, нам нужно понять, что они на самом деле и чем они отличаются от переменных среды. Такие переменные $INTEGER
называются позиционными параметрами. Это описано в стандарте POSIX (интерфейс переносимой операционной системы), раздел 2.1 (выделено мной):
- Оболочка выполняет функцию (см. «Команда определения функции»), встроенную (см. Специальные встроенные утилиты), исполняемый файл или сценарий, предоставляя имена аргументов в качестве позиционных параметров с номерами от 1 до n и имя команды (или в случае функции в сценарии - имя сценария) в качестве позиционного параметра пронумеровано 0 (см. Поиск и выполнение команд).
Напротив, такие переменные, как $HOME
и $PATH
являются переменными среды. Их определение описано в разделе 8 стандарта :
Переменные среды, определенные в этой главе, влияют на работу нескольких утилит, функций и приложений. Существуют и другие переменные среды, которые представляют интерес только для определенных утилит. Переменные среды, которые применяются только к одной утилите, определяются как часть описания утилиты.
Обратите внимание на их описание. Позиционные параметры должны появляться перед командой, т command positional_arg_1 positional_arg_2...
. Е. Они предназначены для предоставления пользователю команды, что конкретно делать. Когда вы это сделаете echo 'Hello' 'World'
, он будет распечатать Hello
и World
строки, потому что это позиционные параметры echo
- вещи , которые вы хотите , echo
чтобы работать дальше. И echo
построен так, что он воспринимает позиционные параметры как строки, которые будут напечатаны (если только они не являются одним из необязательных флагов -n
). Если вы сделаете это с другой командой, он может не понять, что Hello
иWorld
потому что, возможно, он ожидает число. Обратите внимание, что позиционные параметры не «наследуются» - дочерний процесс не знает о позиционных параметрах родителя, если он явно не передан дочернему процессу. Часто вы видите, что позиционные параметры передаются с помощью сценариев-оберток, которые могут проверять уже существующий экземпляр команды или добавлять дополнительные позиционные параметры к реальной команде, которая будет вызвана.
Напротив, переменные среды предназначены для воздействия на несколько программ. Они являются переменными среды , потому что они установлены вне самой программы (подробнее об этом ниже). Определенные переменные среды, такие как HOME
или PATH
имеют определенный формат, конкретное значение, и они будут означать то же самое для каждой программы. HOME
переменная будет означать то же самое для внешней утилиты, например, для /usr/bin/find
вашей оболочки (и, следовательно, для скрипта) - это домашний каталог с именем пользователя, под которым выполняется процесс. Обратите внимание, что переменные среды могут использоваться, например, для учета определенного поведения командыUID
Переменная окружения может использоваться, чтобы проверить, выполняется ли сценарий с правами root или нет, и соответственно перейти к определенным действиям. Переменные среды наследуются - дочерние процессы получают копию родительской среды. Смотрите также Если процессы наследуют родительскую среду, зачем нам экспорт?
Короче говоря, главное различие заключается в том, что переменные среды устанавливаются вне команды и не предназначены для изменения (обычно), в то время как позиционные параметры - это то, что должно обрабатываться командой, и они изменяются.
Не только концепция оболочки
В комментариях я заметил, что вы смешиваете терминал и оболочку и действительно рекомендовали бы вам прочитать о реальных терминалах, которые когда-то были физическими устройствами. В настоящее время «терминал», на который мы обычно ссылаемся, это окно с черным фоном и зеленым текстом на самом деле является программным процессом, процессом. Терминал - это программа, которая запускает оболочку, в то время как оболочка - это тоже программа, но та, которая читает то, что вы вводите для выполнения (то есть, если это интерактивная оболочка; неинтерактивные оболочки - это сценарии и sh -c 'echo foo'
типы вызовов). Подробнее о снарядах здесь .
Это важное различие, но также важно признать, что терминал - это программа, и поэтому он придерживается тех же правил среды и позиционных параметров. Вы gnome-terminal
когда начали будет выглядеть на вашем SHELL
переменном окружение, и нерест соответствующей оболочки по умолчанию для вас, если вы не указали какую - либо другая команды с -e
. Допустим, я изменил свою оболочку по умолчанию на ksh
- ksh
вместо этого появится gnome-терминал bash
. Это также пример того, как среда используется программами. Если я явно указать gnome-terminal
с -e
для запуска конкретной оболочки - он будет делать это, но это не будет постоянным. Напротив, среда должна быть в основном неизменной (подробнее об этом позже).
Итак, как вы можете видеть, переменные окружения и позиционирования являются свойствами процесса / команды, а не просто оболочки. Когда дело доходит до сценариев оболочки, они также следуют модели, установленной языком программирования C. Возьмите, например, main
функцию C, которая обычно выглядит
int main(int argc, char **argv)
где argc
число аргументов командной строки и argv
фактически массив параметров командной строки, а затем есть environ
функция (в Linux man -e 7 environ
) для доступа к таким вещам, как путь к домашнему каталогу пользователя, список каталогов, в PATH
которых мы можем искать исполняемые файлы и т. д. Сценарии оболочки также моделируются аналогичным образом. В оболочечной терминологии, мы имеем позиционные параметры $1
, $2
и так далее, в то время как $#
это количество позиционных параметров. Как насчет $0
? Это имя самого исполняемого файла, который также смоделирован на языке программирования C - argv[0]
будет именем вашего C "исполняемого файла". И это справедливо для большинства языков программирования и сценариев .
Интерактивные против неинтерактивных оболочек
Одна из вещей, которые я уже намекнул, - это различие между интерактивными и неинтерактивными оболочками . Подсказка, где вы вводите команды - это интерактивно, оно взаимодействует с пользователем. В отличие от этого, когда у вас есть сценарий оболочки или вы запускаете bash -c''
, он не интерактивен.
И именно здесь различие становится важным. Оболочка, которую вы уже запускаете, представляет собой процесс, который был порожден позиционными параметрами (для bash
оболочки входа в систему - один "..., чей первый символ нулевого аргумента - -, или тот, который запущен с параметром --login." ( Ссылка ) )
В отличие от сценариев и оболочек, запущенных с -c
параметром, могут использоваться аргументы $1
и $2
аргументы. Например,
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
Обратите внимание, что я также использовал sh
там, потому что небольшая особенность -c
опции заключается в том, чтобы взять первый позиционный параметр и назначить его $0
, в отличие от того, что обычно является именем программы.
Еще одна вещь, которую важно отметить, это то, что позиционные параметры - это то, что я называю «изменяемым». Обратите внимание, как мы впервые запустили bash
свои собственные позиционные параметры, но эти позиционные параметры стали параметрами для echo
и stat
. И каждая программа понимает это по-своему. Если мы передадим stat
строку, Hello World
а файла нет, Hello World
это приведет к ошибке; bash
обрабатывает его как простую строку, но stat
ожидает, что эта строка будет существующим именем файла. Напротив, все программы согласны с тем, что переменная окружения HOME
является каталогом (если программист не кодирует ее необоснованным образом).
Можем ли мы возиться с переменными среды и позиционными параметрами?
Технически, мы можем возиться с обоими, но мы не должны возиться с переменными среды, в то время как нам часто приходится предоставлять позиционные параметры. Мы можем запускать команды в оболочке с добавлением переменной, например:
$ hello=world bash -c 'echo $hello'
world
Мы также можем помещать переменные в среду просто используя export variable=value
оболочку или скрипт. Или мы можем запустить команду с полностью пустой средой с помощью env -c command arg1 arg2
. Однако, как правило, не рекомендуется возиться с окружением, особенно с использованием переменных верхнего регистра или перезаписи уже существующих переменных окружения. Обратите внимание, что рекомендуется, хотя и не стандарт.
Для позиционных параметров способ их установки очевиден, просто добавьте их к команде, но также есть способы установить их другими способами , а также изменить список этих параметров с помощью shift
команды.
В заключение, цель этих двух различна, и они существуют по причине. Я надеюсь, что люди получили некоторое представление об этом ответе, и было весело читать его так же, как я написал этот ответ.
Примечание по команде set
Команда set
, в соответствии с руководством ведет себя так (из руководства Bash, выделение добавлено):
Без параметров имя и значение каждой переменной оболочки отображаются в формате, который можно повторно использовать в качестве входных данных для установки или сброса текущих установленных переменных.
Другими словами, set
рассматриваются переменные, специфичные для оболочки, например, некоторые из которых находятся в среде HOME
. В отличие от команд, как env
и printenv
посмотреть на фактическую переменную среды, с которой запускается команда. Смотрите также это .
export 3
можете превратиться$3
в переменную окружения. Вы не можетеunset 3
; и вы не можете присвоить$3
новое значение, используя3=val
.