В чем разница между "source x", ". X" и "./x" в Bash?

У меня есть один источник 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 выполнение.

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

3 ответа

Решение

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

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

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

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

Три способа:

Вы можете заключить скрипт в функцию и использовать только 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

Думайте о команде "источник" как в операторе "включить". Он берет содержимое аргумента и запускает его так, как если бы он был запущен напрямую. В этом случае ваша команда '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 с символом "." представляющий вашу текущую папку.

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