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


86

У меня есть 2 сценария оболочки.

Второй сценарий оболочки содержит следующие функции second.sh

func1 
func2

First.sh вызовет второй сценарий оболочки с некоторыми параметрами и вызовет func1 и func2 с некоторыми другими параметрами, специфичными для этой функции.

Вот пример того, о чем я говорю

second.sh

val1=`echo $1`
val2=`echo $2`

function func1 {

fun=`echo $1`
book=`echo $2`

}

function func2 {

fun2=`echo $1`
book2=`echo $2`


}

first.sh

second.sh cricket football

func1 love horror
func2 ball mystery

Как я могу этого добиться?



3
v=$(echo $1)полностью избыточен. Просто напишите fun2=$1. Единственная разница в том, что $()(или обратные кавычки) удаляют завершающие символы новой строки.
Уильям Перселл

1
Поскольку нет ничего особенного в вызове функции из сценария оболочки, а не из командной строки, этот вопрос можно свести к «Как вызвать функцию bash?»
Том Рассел

Ответы:


145

Выполните рефакторинг вашего second.shскрипта следующим образом:

function func1 {
   fun=$1
   book=$2
   printf "fun=%s,book=%s\n" "${fun}" "${book}"
}

function func2 {
   fun2=$1
   book2=$2
   printf "fun2=%s,book2=%s\n" "${fun2}" "${book2}"
}

А затем вызовите эти функции из скрипта first.shследующим образом:

source ./second.sh
func1 love horror
func2 ball mystery

ВЫХОД:

fun=love,book=horror
fun2=ball,book2=mystery

12
Чтобы избежать непреднамеренных побочных эффектов, помните, что sourceкоманда действительно запускает сценарий, переданный в качестве аргумента.
dvlcube 02

43

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

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

. /path/to/functions.sh

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


3
Разве это не то же самое, что принятый ответ, поскольку .это псевдоним для source?
ajsharma

9
Ну, я ответил первым, так что технически принятый ответ такой же, как этот :). Кроме того, while sourceявляется псевдонимом для .многих оболочек, но это не всегда так. Например, в dashпакете Debian, который предоставляет /bin/sh, нет sourceкоманды.
larsks

sourceкоманда не работала в Ubuntu @ajsharma. Ссылка: исходная команда не найдена в sh shell
rajeshmag

так странно, что за этот комментарий не проголосовали как за самый высокий? Это правильный синтаксис #! / Bin / sh, а другой будет работать только в bash.
xddq

20

Проблема

Принятый в настоящее время ответ работает только при важном условии. Дано...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

а также

/foo/bar/second.sh:

#!/bin/bash

source ./first.sh
func1 World

это работает только в том случае, если first.shвыполняется из того же каталога, в котором first.shнаходится. Т.е. если текущий рабочий путь оболочки - /fooпопытка запустить команду

cd /foo
./bar/second.sh

выводит ошибку:

/foo/bar/second.sh: line 4: func1: command not found

Это связано с тем, что он source ./first.shотносится к текущему рабочему пути, а не к пути скрипта. Следовательно, одним из решений может быть использование подоболочки и запуск

(cd /foo/bar; ./second.sh)

Более общее решение

Дано...

/foo/bar/first.sh:

function func1 {  
   echo "Hello $1"
}

а также

/foo/bar/second.sh:

#!/bin/bash

source $(dirname "$0")/first.sh

func1 World

тогда

cd /foo
./bar/second.sh

печатает

Hello World

Как это работает

  • $0 возвращает относительный или абсолютный путь к выполненному скрипту
  • dirname возвращает относительный путь к каталогу, в котором существует скрипт $ 0
  • $( dirname "$0" )dirname "$0"команда возвращает относительный путь к директории исполняемого скрипта, который затем используется в качестве аргумента для sourceкоманды
  • в "second.sh" /first.shпросто добавляется имя импортированного сценария оболочки
  • source загружает содержимое указанного файла в текущую оболочку

0

Если вы определите

    #!/bin/bash
        fun1(){
          echo "Fun1 from file1 $1"
        }
fun1 Hello
. file2 
fun1 Hello
exit 0

в file1 (chmod 750 file1) и file2

   fun1(){
      echo "Fun1 from file2 $1"
    }
    fun2(){
      echo "Fun1 from file1 $1"
    }

и запустите ./file2 вы получите Fun1 от file1 Hello Fun1 от file2 Hello Surprise !!! Вы перезаписываете fun1 в file1 на fun1 из file2 ... Чтобы не делать этого, вы должны

declare -f pr_fun1=$fun1
. file2
unset -f fun1
fun1=$pr_fun1
unset -f pr_fun1
fun1 Hello

он сохраняет ваше предыдущее определение для fun1 и восстанавливает его с предыдущим именем, удаляя ненужное импортированное. Каждый раз, когда вы импортируете функции из другого файла, вы можете помнить два аспекта:

  1. вы можете перезаписать существующие с теми же именами (если это то, что вам нужно, вы должны сохранить их, как описано выше)
  2. импортировать все содержимое файла импорта (функции и глобальные переменные). Будьте осторожны! Это опасная процедура

-5
#vi function.sh

#!/bin/bash
f1() {
    echo "Hello $name"
}

f2() {
    echo "Enter your name: "
    read name
    f1
}
f2

#sh function.sh

Здесь функция f2вызовет функциюf1

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.