Существует ли различие между и “источник” в ударе, в конце концов?

Я искал различие между "." и "источник", встроенные команды и несколько источников (например, в этом обсуждении и странице справочника удара) предполагают, что это все равно.

Однако после проблемы с переменными среды, я провел тест. Я создал файл testenv.sh это содержит:

#!/bin/bash
echo $MY_VAR

В командной строке я выполнил следующее:

> chmod +x testenv.sh
> MY_VAR=12345
> ./testenv.sh

> source testenv.sh
12345
> MY_VAR=12345 ./testenv.sh
12345

[обратите внимание, что 1-я форма возвратила пустую строку]

Так, этот небольшой эксперимент предполагает, что существует различие, в конце концов, где для "исходной" команды, дочерняя среда наследовала все переменные от родительской, где для "." этого не делает.

Я пропускаю что-то или, это - недокументированное / устаревшая функция удара?

[Удар GNU, версия 4.1.5 (1) - выпуск (x86_64-pc-linux-gnu)]

38
задан 13 April 2017 в 05:24

2 ответа

Короткий ответ

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

Расширенное объяснение

Это - синтаксис source встроенная оболочка, который выполняет содержание сценария в текущей оболочке (и таким образом с переменными текущей оболочки):

source testenv.sh

Это - синтаксис . встроенный, который действительно делает то же самое как source:

. testenv.sh

Однако этот синтаксис запускает скрипт как исполняемый файл, запуская новую оболочку для выполнения его:

./testenv.sh

Это не использует . встроенный. Скорее . часть пути к файлу, который Вы выполняете. Вообще говоря, можно выполнить любой исполняемый файл в оболочке путем вызова его с именем, которое содержит по крайней мере один / символ. Петлять в текущем каталоге, предшествуя ему ./ таким образом самый легкий путь. Если текущий каталог не находится в Вашем PATH, Вы не можете запустить скрипт с командой testenv.sh. Это должно предотвратить людей из случайно выполняющихся файлов в текущем каталоге, когда они намереваются выполнить системную команду или некоторый другой файл, который существует в некотором каталоге, перечисленном в PATH переменная среды.

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

  1. Переменная оболочки была экспортирована, заставив это быть переменной среды. Используйте export оболочка, встроенная для этого. В Вашем примере можно использовать export MY_VAR=12345 чтобы установить и экспортировать переменную за один шаг, или если это уже установлено, можно просто использовать export MY_VAR.

  2. Переменная оболочки явно установлена и передана для команды, которую Вы выполняете, вызывая ее быть переменной среды на время выполняемой команды. Это обычно выполняет это:

    MY_VAR=12345 ./testenv.sh
    

    Если MY_VAR переменная оболочки, которая не была экспортирована, можно даже работать testenv.sh с MY_VAR переданный как переменная среды путем установки его на себя:

    MY_VAR="$MY_VAR" ./testenv.sh
    

./ Синтаксис для сценариев требует, чтобы строка Hashbang работала (правильно)

Между прочим, обратите внимание на то, что, когда Вы вызываете исполняемый файл по имени как выше (а не с . или source окружите созданный-ins), что программная оболочка используется для выполнения, она обычно не определяется, какой оболочкой Вы выполняете ее от. Вместо этого:

  • Для двоичных файлов ядро может быть настроено для петляния того конкретного типа. Это исследует первые два байта файла для "магического числа", которое указывает, какой двоичный исполняемый файл это. Это - то, как исполняемые двоичные файлы могут работать.

    Это, конечно, чрезвычайно важно, потому что сценарий не может работать без оболочки или другого интерпретатора, который является исполняемым двоичным файлом! Плюс, много команд и приложений являются скомпилированными двоичными файлами, а не сценариями.

    (#! текстовое представление "магического числа", указывающего на текстовый исполняемый файл.)

  • Для файлов, которые, как предполагается, работают в оболочке или другом интерпретируемом языке, первая строка похожа:

    #!/bin/sh
    

    /bin/sh может быть заменен тем, что другая оболочка или интерпретатор предназначается для запущения программы. Например, программа Python могла бы запуститься со строки:

    #!/usr/bin/python
    

    Эти строки называют hashbang, хижиной и многими другими аналогичными именами. Посмотрите эту запись FOLDOC, эту статью Wikipedia, и #!/bin/sh считанный интерпретатором? для получения дополнительной информации.

  • Если текстовый файл отмечен исполняемый файл, и Вы выполняете его от своей оболочки (как ./filename) но это не начинается #!, ядру не удается выполнить его. Однако видя, что это произошло, Ваша оболочка попытается выполнить его путем передачи ее имени к некоторой оболочке. Существует немного требований, помещенных в то, какая оболочка, которая является ("оболочка выполню команду, эквивалентную вызову оболочки..."). На практике, некоторые оболочки - включая bash* - выполните другой экземпляр себя, в то время как другие используют /bin/sh. Я настоятельно рекомендую, чтобы Вы избежали этого и использовали hashbang строку вместо этого (или запустили скрипт путем передачи его желаемому интерпретатору, например, bash filename).

    *руководство Bash GNU, 3.7.2 Поисков Команды и Выполнение: "Если это выполнение перестало работать, потому что файл не находится в формате исполняемых файлов, и файл не является каталогом, это, как предполагается, сценарий оболочки, и оболочка выполняет его, как описано в Сценариях оболочки".

68
ответ дан 23 November 2019 в 00:13

Да, Вы пропускаете что-то.

я думаю, что Вы путаете '.', который означает текущий каталог, как в ./testenv.sh и '.', который означает source (который является встроенной командой). Таким образом в случае, когда'.' средства source это было бы . ./testenv.sh. Иметь смысл?

Так пробуют это:

MY_VAR=12345 
. ./testenv.sh
13
ответ дан 23 November 2019 в 00:13

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

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