Как вызвать один сценарий оболочки из другого сценария оболочки?

740

У меня есть два сценария оболочки, a.shи b.sh.

Как я могу позвонить b.shиз сценария оболочки a.sh?

Praveen
источник
8
Можете ли вы дать некоторые подробности: какую ОС и какую оболочку (и) или вы просто говорите об этой проблеме в принципе ?? Пример кода также будет полезен.
jsalonen
14
Это на самом деле не конкретный вопрос, и при этом он не демонстрирует предварительных усилий по решению проблемы.
Крис
1
У меня была одна проблема: у меня b.shне было прав на выполнение. Это может быть хорошая вещь, чтобы проверить.
seth10
Добавьте ./перед именем сценария, например, вместо:, b.shиспользуйте:./b.sh
Бенни
2
Если кто-то продолжает получать сообщение No such file or directoryоб ошибке stackoverflow.com/a/2920431/1356559
Амр Лотфи

Ответы:

960

Есть несколько способов сделать это:

  1. Сделайте другой сценарий исполняемым, добавьте #!/bin/bashстроку вверху и путь к файлу к переменной среды $ PATH. Тогда вы можете вызвать его как обычную команду;

  2. Или вызвать его с помощью sourceкоманды (псевдоним .), как это source /path/to/script:;

  3. Или использовать bashкоманду для его выполнения: /bin/bash /path/to/script;

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

Во втором методе, если вы используете exitвторой скрипт, он также завершит работу первого скрипта. Что не произойдет в первом и третьем способах.

Какой-то программист чувак
источник
30
помните, chmod a+x /path/to/fileиначе он не будет исполняемым. Относится только к методу ./script.
Натан Лилиенталь
3
Не забудьте изменить формат / кодировку исполняемых файлов в Unix, если они созданы в DOS и затем загружены в среду Unix -> dos2unix <имя сценария>
Abhishek Chatterjee
3
@cecemel Первый и третий способ может быть «асинхронным» с использованием обычного синтаксиса run-in-background.
Какой-то программист чувак
16
Проблема в sourceтом, что exitоператор в вызываемом скрипте тоже выйдет из вашего ...
Охад Шнайдер
18
@ user528025 .- это не псевдоним для source, а наоборот. sourceявляется расширением bash, но .работает в любой POSIX-совместимой оболочке.
Score_Under
207

Проверь это.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
источник
4
Это предполагает, что script.sh находится в том же каталоге, что и любой скрипт, который выполняется. Если бы вы хотели вызвать сценарий где-то еще, вы бы сказалиsh <path to script>/script.sh
Морган Кеньон
32
Это также использует две оболочки, bashи sh. Даже когда shна самом деле bashэто не ведет себя так же. Если вы используете, #!/bin/bashто вы, вероятно, захотите использовать bash script.sh(или просто ./script.shиспользовать хэш-банг этих скриптов).
Мартин Турной
1
Получал ошибку «Отказано в доступе», даже когда я установил chmod +xв .sh файл. Какие-либо предложения?
Исаак погода
@isaacweathers попробуй chmod 777
Янак Мина
114

Есть несколько способов сделать это. Терминал для выполнения скрипта:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

Все это правильно для пути с пробелами !!!

Андрей Красуцкий
источник
41
Каковы их различия? Почему один, почему другой?
rocketspacer
, «$ SCRIPT_PATH» предпочтительнее
Гарри Мамфорд-Тернер
1
Я могу просто добавить, что они не все эквивалентны, например, sh "$ SCRIPT_PATH" и bash "$ SCRIPT_PATH" не будут запускать скрипт #! / Usr / bin / Ожидайте, тогда как просто "$ SCRIPT_PATH" будет.
Тахлор
58

Ответ, который я искал:

( exec "path/to/script" )

Как уже упоминалось, execзаменяет оболочку без создания нового процесса. Тем не менее , мы можем поместить его в подоболочку, что делается с помощью паратезов.

РЕДАКТИРОВАТЬ: На самом деле ( "path/to/script" )достаточно.

Максим Четруска
источник
11
Это кажется довольно запутанным. Почему бы просто не позвонить /path/to/script? Я не вижу необходимости execвообще здесь?
Мартин Турной
Подобная оболочка также не нужна, так как вы не используете exec.
Карел Влк
6
как бы вы выполнили этот скрипт с аргументами?
Bhargav
Если вы все еще хотите захватить вывод
подскрипта,
@Bhargav по этой ссылке stackoverflow.com/questions/14302389/...
tpbafk
16

Зависит от. Вкратце ... Если вы хотите загрузить переменные на текущей консоли и выполнить, вы можете использовать их source myshellfile.shв своем коде. Пример:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Если вы просто хотите выполнить файл, и единственное, что вас интересует - это результат, вы можете сделать:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Я надеюсь, поможет вам. Спасибо.

Дуглас Бонафе
источник
2
Обратите внимание, что sourceэто особенность Bash. Стандартная оболочка Bourne имеет только .(например . other_script.sh).
Мартин Турной
15

Вы можете использовать /bin/shдля вызова или выполнения другого скрипта (через ваш реальный скрипт):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

Выход будет:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ранджиткумар Т
источник
1
Конечно, это будет работать showdate.shпод / bin / sh, а не / bin / bash?
Крис Уоттс
Я попытался с " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" и запустил файл: mainscript.sh и получил тот же вывод.
Ранджиткумар Т
10

Просто добавьте в строку все, что вы набрали бы в терминале, чтобы выполнить скрипт!
например:

#!bin/bash
./myscript.sh &

если скрипт, который нужно выполнить, не находится в той же директории, просто используйте полный путь скрипта.
например: `/ home / user / script-directory /./ myscript.sh &

скоро
источник
@Carpetsmoker &для фоновой задачи
Андрей Красуцкий,
9

Сначала вы должны включить файл, который вы называете:

#!/bin/bash
. includes/included_file.sh

тогда вы вызываете свою функцию так:

#!/bin/bash
my_called_function
Гази Трики
источник
9

Простой источник поможет вам. Например

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Нитин Джаваркар
источник
9

Если у вас есть другой файл в том же каталоге, вы можете сделать:

bash another_script.sh

или

source another_script.sh

или

. another_script.sh

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

Шиталь шах
источник
5

Верхний ответ предполагает добавление #!/bin/bashстроки в первую строку вызываемого подпрограммы. Но даже если вы добавите shebang, гораздо быстрее * запустить скрипт в под-оболочке и записать вывод:

$(source SCRIPT_NAME)

Это работает, когда вы хотите продолжать запускать один и тот же интерпретатор (например, от bash к другому bash-скрипту) и гарантирует, что строка shebang подпрограммы не будет выполнена.

Например:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Вывод:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Например, когда на устройстве запущены средства защиты от вирусов или вирусов, для запуска нового процесса могут потребоваться дополнительные 100 мс.

cmcginty
источник
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Абденнур ТУМИ
источник
4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?
Валеро
источник
1
неверно scriptPathscriptName
Андрей Красуцкий,
3

Предположим, что новый файл "/ home / satya / app / app_specific_env" и содержимое файла выглядит следующим образом

#!bin/bash

export FAV_NUMBER="2211"

Добавить ссылку на этот файл в файл ~ / .bashrc

source /home/satya/app/app_specific_env

Каждый раз, когда вы перезагружаете машину или перезагружаетесь, попробуйте echo $FAV_NUMBERв терминале. Это выведет значение.

На всякий случай, если вы хотите увидеть эффект сразу, source ~/.bashrcв командной строке.

Сатья Каллури
источник
3
chmod a+x /path/to/file-to-be-executed

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

Благодаря комментарию @Nathan Lilienthal

Asqan
источник
1

Есть проблемы с импортом функций из другого файла.
Первое : вам не нужно делать этот файл исполняемым. Лучше не делать этого! просто добавь

. file

импортировать все функции. И все они будут, как если бы они были определены в вашем файле.
Второе : вы можете определить функцию с тем же именем. Это будет перезаписано. Это плохо. Вы можете заявить, что так

declare -f new_function_name=old_function_name 

и только после этого делать импорт. Таким образом, вы можете вызвать старую функцию под новым именем.
Третье : вы можете импортировать только полный список функций, определенных в файле. Если некоторые из них не нужны, вы можете сбросить их. Но если вы переписываете свои функции после сброса, они будут потеряны. Но если вы установите ссылку на него, как описано выше, вы можете восстановить после сброса с тем же именем.
в заключениеВ общем процедура ввоза опасна и не так проста. Быть осторожен! Вы можете написать скрипт, чтобы сделать это более простым и безопасным. Если вы используете только часть функций (не все), лучше разбить их на разные файлы. К сожалению, эта техника не очень хорошо работает в Bash. Например, в python и некоторых других языках сценариев это просто и безопасно. Возможен частичный импорт только необходимых функций со своими именами. Мы все хотим, чтобы в следующих версиях куста была сделана та же функциональность. Но теперь мы должны написать много дополнительных кодов, чтобы делать то, что вы хотите.

Анатолий
источник
(Добро пожаловать в SO!) Поскольку пользователя Praveen в последний раз видели в 2011 году, непросто будет выяснить, был ли вопрос, как заставить оболочку, выполняющую a.sh, выполнить b.sh (и продолжить выполнение a.sh, если нет заповедал иначе ), или в буквальном смысле вызова b.sh . (Моя проверка орфографии не поймать bush versions.) (У вас есть кто - то , чтобы обратиться , чтобы помочь вам с английской грамматики (Иногда хочу я?).)
пожилой человек
0

Используйте backticks.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Затем извлеките вывод сценария производителя в качестве аргумента сценария потребителя.

dacabdi
источник