Краткий ответ
В вашем вопросе вторая команда не использует ни .
встроенную оболочку, ни source
встроенную. Вместо этого вы на самом деле запускаете сценарий в отдельной оболочке, вызывая его по имени, как и в случае с любым другим исполняемым файлом. Это дает ему отдельный набор переменных (хотя, если вы экспортируете переменную в ее родительскую оболочку, она будет переменной окружения для любого дочернего процесса и, следовательно, будет включена в переменные дочерней оболочки ). Если вы измените на /
пробел, он запустится со .
встроенным, что эквивалентно source
.
Расширенное объяснение
Это синтаксис source
встроенной оболочки, которая выполняет содержимое скрипта в текущей оболочке (и, следовательно, с переменными текущей оболочки):
source testenv.sh
Это синтаксис .
встроенного, который делает то же самое, что и source
:
. testenv.sh
Однако этот синтаксис запускает скрипт как исполняемый файл и запускает новую оболочку для его запуска:
./testenv.sh
Это не использование .
встроенного. Скорее, .
это часть пути к файлу, который вы выполняете. Вообще говоря, вы можете запустить любой исполняемый файл в оболочке, вызвав его с именем, которое содержит хотя бы один /
символ. ./
Таким образом, запустить файл в текущем каталоге, предшествуя ему, является самым простым способом. Если текущий каталог не находится в вашем PATH
, вы не можете запустить скрипт с помощью команды testenv.sh
. Это сделано для того, чтобы люди не могли случайно выполнить файлы в текущем каталоге, когда они намереваются выполнить системную команду или какой-либо другой файл, который существует в каком-либо каталоге, указанном в PATH
переменной среды.
Поскольку запуск файла по имени (а не с помощью source
или .
) запускает его в новой оболочке, он будет иметь свой собственный набор переменных оболочки. Новая оболочка наследует переменные среды от вызывающего процесса (в данном случае это ваша интерактивная оболочка), и эти переменные среды становятся переменными оболочки в новой оболочке. Однако для передачи переменной оболочки в новую оболочку должно быть выполнено одно из следующих действий:
Переменная оболочки была экспортирована, в результате чего она стала переменной окружения. Используйте export
встроенную оболочку для этого. В вашем примере вы можете использовать export MY_VAR=12345
для установки и экспорта переменную за один шаг, или, если она уже установлена, вы можете просто использовать export MY_VAR
.
Переменная оболочки задается явно и передается для команды, которую вы запускаете, поэтому она будет переменной среды на время выполнения команды. Это , как правило , выполняет следующее :
MY_VAR=12345 ./testenv.sh
Если MY_VAR
это переменная оболочки, которая не была экспортирована, вы даже можете запустить testenv.sh
с параметром MY_VAR
передается как переменная среды, установив ее себе :
MY_VAR="$MY_VAR" ./testenv.sh
./
Синтаксис для сценариев требует, чтобы работала строка Hashbang (правильно)
Кстати, обратите внимание, что когда вы вызываете исполняемый файл по имени, как указано выше (а не со встроенными модулями .
или source
shell), то, какая программа оболочки используется для ее запуска, обычно не определяется тем, из какой оболочки вы ее запускаете , Вместо:
Для двоичных файлов ядро может быть настроено для запуска файлов этого конкретного типа. Он проверяет первые два байта файла на «магическое число», которое указывает, какой это двоичный исполняемый файл. Вот как исполняемые двоичные файлы могут работать.
Это, конечно, чрезвычайно важно, потому что скрипт не может работать без оболочки или другого интерпретатора, который является исполняемым двоичным файлом! Кроме того, многие команды и приложения являются скомпилированными двоичными файлами, а не скриптами.
( #!
является текстовым представлением «магического числа», указывающего на исполняемый текст.)
Для файлов, которые должны работать в оболочке или другом интерпретируемом языке, первая строка выглядит следующим образом:
#!/bin/sh
/bin/sh
может быть заменено любой другой оболочкой или интерпретатором, предназначенным для запуска программы. Например, программа на Python может начинаться со строки:
#!/usr/bin/python
Эти строки называются hashbang, shebang и рядом других похожих имен. Посмотрите эту запись FOLDOC , эту статью в Википедии и прочитал ли интерпретатор #! / Bin / sh? за дополнительной информацией.
Если текстовый файл помечен как исполняемый, и вы запускаете его из своей оболочки (например ./filename
), но он не начинается с #!
, ядро не может его выполнить. Однако, увидев, что это произошло, ваша оболочка попытается запустить ее, передав ее имя некоторой оболочке. Есть несколько требований , помещенных на то , что оболочку , которая является ( «оболочка должны выполнить команду , эквивалентную имеющей оболочку вызов ...» ). На практике некоторые оболочки - включая bash
* - запускают другой экземпляр сами, в то время как другие используют/bin/sh
, Я настоятельно рекомендую вам избегать этого и использовать вместо этого строку хэш-банга (или запустить скрипт, передав его нужному интерпретатору, например bash filename
).
* Руководство по GNU Bash , 3.7.2 Поиск и выполнение команд : «Если это выполнение завершится неудачно, потому что файл не в исполняемом формате, и файл не является каталогом, предполагается, что это сценарий оболочки, а оболочка выполняет его, как описано в сценариях оболочки ".
source
это то, что функции стали доступны из bash без необходимости загружать или запускать снова. Пример#!/bin/bash function olakease {echo olakease;}
. Как только вы загрузите его,source file.sh
вы можете напрямую звонитьolakease
из bash. Мне действительно это нравится. Исходный код выполняет, затем загружает много вещей, точка.
предназначена только для выполнения и является чем-то вроде использованияbash file.sh
.
имеет такое же поведение:. file.sh
иsource file.sh
делает то же самое, включая сохранение функций, определенных вfile.sh
. (Возможно, вы думаете о том./file.sh
, что отличается. Но это не использует.
встроенное; вместо этого,.
это часть пути.)Да, ты что-то упустил.
Я думаю, что вы путаете '.' это означает текущий каталог, как в
./testenv.sh
и '.' это означаетsource
(что является встроенной командой). Так и в случае, когда «.» значитsource
будет. ./testenv.sh
. Есть смысл?Так что попробуйте это:
источник
./
сообщает ему, где именно файл, без него, bash сначала просматривает PATH, а затем пробует текущий каталог, если не нашел его. Если bash работает в режиме POSIX, и вы не указали путь к файлу (например./
), он будет искать только в PATH и не сможет найти файл, если текущий каталог не в PATH.source
(и.
) на самом деле сначала будете проверять $ PATH, даже если они не совсем запускают скрипт в обычном смысле. Мой (бывший) комментарий был неверным.