В чем разница между поиском ('.' Или 'source') и выполнением файла в bash?


76

В чем разница между выполнением скрипта, подобного этому:

./test.sh

и выполнить скрипт, как это:

. test.sh?

Я попробовал простой двухстрочный скрипт, чтобы посмотреть, смогу ли я найти разницу:

#!/bin/bash
ls

Но оба . test.shи ./test.shвернули одну и ту же информацию.


Извиняюсь, если это дубликат - после дальнейшего изучения я нашел несколько страниц с соответствующей информацией, выполнив поиск «bash dot» вместо «bash».
Натан

3
Точно так же, как test.shэто не то же самое, что ./test.sh(первое вызывает PATHпоиск), так . test.shи они . ./test.shразличны (первое вызывает PATHпоиск). Кажется, что многие оболочки неявно включаются .в конце PATHпри .поиске пути, но это поведение не является стандартным. Таким образом, точнее сравнивать test.shпротив . test.shи ./test.shпротив . ./test.sh.
jw013

Ответы:


83

./test.shработает test.shкак отдельная программа. Это может быть сценарий bash, если файл test.shначинается с #!/bin/bash. Но это может быть что-то совсем другое.

. ./test.shвыполняет код файла test.shвнутри запущенного экземпляра bash. Он работает так, как будто файл содержимого test.shбыл включен в текстовом формате вместо . ./test.shстроки. (Почти: есть некоторые детали, которые отличаются, например, значение $BASH_LINENOи поведение returnвстроенного.)

source ./test.shидентичен . ./test.shin bash (в других оболочках sourceможет немного отличаться или не существовать вообще; .включение включено в стандарт POSIX).

Наиболее заметная разница между выполнением отдельного сценария со встроенным сценарием ./test.shи включением в него .заключается в том, что если test.shсценарий устанавливает некоторые переменные среды с отдельным процессом, то устанавливается только среда дочернего процесса, тогда как при включении сценария среда единственного процесса оболочки установлен. Если вы добавите строку foo=barв test.shи echo $fooв конце вызывающего скрипта, вы увидите разницу:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar

17
Также добавление echo $$в скрипт покажет разницу довольно четко. $$Переменная содержит PID текущей оболочки.

1
Другой сценарий использования - использование . ./test.shвызова из другого сценария оболочки для использования функций, описанных в test.sh. Я имею в виду, что вы можете устанавливать не только переменные, вы также можете создавать новые функции, которые затем можно вызывать из bash или другого скрипта. . /usr/libexec/company/tools; custom_command "variable"
Rqomey

9

Запуск сценария первым способом запускает его как дочерний процесс. Sourcing (второй способ), с другой стороны, запускает сценарий, как если бы вы ввели все его команды в текущую оболочку - если сценарий устанавливает переменную, он останется установленным, если сценарий завершится, сеанс завершится. Смотрите help .документацию.


3

Еще одна вещь, на которую я обращаю внимание, это то, что если у вас есть псевдоним:

# add into .bashrc_aliases
alias ls='ls -lht'

При этом ./test.shвы получите нормальный lsвывод (и PID, отличный от текущей оболочки):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

С помощью . test.shили . ./test.shвы получите более подробный вывод (и тот же PID, что и у текущей оболочки):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID

Вы можете включить это в .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi Затем, вставьте свои псевдонимы .bash_aliases.
Авраам

Конечно, но вам все еще не нужно использовать aliasключевое слово? (Может быть, это просто ошибка в вашем посте - в строке 3?)
Эмануэль Берг

совершенно правильно, моя ошибка Спасибо @EmanuelBerg
Авраам

-1

Основное использование для меня source(или .) - это функции bash .

У меня есть скрипты со многими функциями, и я выполняю их все с помощью своих .bashrc. Функции «становятся» командами, которые я часто использую.


Я испробовал все три метода в .bashrc - исходный код, абсолютную позицию скрипта и имя команды (размещение скрипта в папке PATH) - и все три метода работали.
Эмануэль Берг
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.