В чем разница между «источником х», «. х »и« ./x »в Баше?

11

У меня есть один источник bash, run.shкак показано ниже:

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

когда я выполняю его двумя способами, это ведет себя по-разному. Первый способ

source run.sh

Он закроет терминал после выполнения. Второй способ

./run.sh

это просто завершит выполнение скрипта и останется на терминале. Я спрашиваю, есть ли команда для выхода из скриптов bash для обоих source run.shи ./run.shвыполнения. Я тоже пытался return, что не очень хорошо работает при ./run.shисполнении.

В целом, меня интересует, почему это происходит, и в чем разница между использованием «источника» и «». для выполнения скрипта?

Ричард
источник

Ответы:

16

Прежде чем ответить, я думаю, что некоторые разъяснения необходимы. Давайте проанализируем следующие три строки:

source run.sh
. run.sh
./run.sh

Первые две строки абсолютно идентичны: .фактически это псевдоним для source. Что sourceделает, это выполнение сценария оболочки в текущем контексте, следовательно, вызов exitзавершит работу оболочки.

Третья строка (которая вас смущает) не имеет ничего общего с другими. ./run.shэто просто путь, и такой же, как (например) /home/user/run.shили /usr/bin/something. Всегда помните, что команды в оболочке разделяются пробелом. Таким образом, в этом случае команда не является ., а есть ./run.sh: это означает, что будет выполнена под-оболочка, и что это exitповлияет только на под-оболочку.

Андреа Корбеллини
источник
5

Три способа:

Вы можете заключить скрипт в функцию и использовать только return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Вы можете проверить, является ли сценарий источником интерактивной оболочки.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Вы можете попытаться вернуться, и, если это не удастся, выйти.

return 1 2>/dev/null || exit 1
geirha
источник
Есть намеки на то, как $- = *i* работает магическое заклинание ?
deadbeef404
@ deadbeef404 Специальный параметр -содержит флаги активных в данный момент параметров. Тест проверяет, -iактивен ли флаг. См gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha
1

Думайте о команде «source» как в «include». Он берет содержимое аргумента и запускает его так, как если бы он был запущен напрямую. В этом случае ваша команда 'source' с аргументом 'run.sh', а run.sh выполняется точно так же, как если бы вы ввели содержимое run.sh в вашу командную строку.

Когда вы запускаете «./run.sh», «./run.sh» является вашей командой и не имеет аргументов. Поскольку этот файл является обычным текстом, а не двоичным, ваша оболочка ищет интерпретатор в shebang ('#!' В первой строке) и находит '/ bin / bash'. Таким образом, ваша оболочка затем запускает новый экземпляр bash, и содержимое run.sh запускается внутри этого нового экземпляра.

В первом случае, когда bash достигает команды exit, она выполняется точно так же, как если бы вы ввели ее в командную строку. Во втором случае это выполняется в процессе bash, который запустила ваша оболочка, поэтому только этот экземпляр bash получает команду 'exit'.

Когда вы вводите строку в bash, все, что находится перед первым пробелом, обрабатывается как команда, а все последующее - как аргументы. Команда '.' является псевдонимом «источник». Когда ты бежишь ». run.sh 'the'. ' это отдельная команда, так как она отделена от аргументов пробелом. Когда вы запускаете «./run.sh», ваша команда «./run.sh» и «.» является частью относительного пути к run.sh с символом «.» представляющий вашу текущую папку.

smokes2345
источник
Если вы программист на C / C ++ и хотите лучше работать со сценариями shell / bash, это идеальный ответ.
Джастин