Подтвердить что ты не робот

Импорт функций из оболочки script

У меня есть оболочка script, которую я хотел бы протестировать с помощью shUnit. script (и все функции) находятся в одном файле, так как упрощают установку.

Пример для script.sh

#!/bin/sh

foo () { ... }
bar () { ... }

code

Я хотел написать второй файл (который не нужно распространять и устанавливать) для проверки функций, определенных в script.sh

Что-то вроде run_tests.sh

#!/bin/sh

. script.sh

# Unit tests

Теперь проблема заключается в . (или source в Bash). Он не только анализирует определения функций, но также выполняет код в script.

Так как script без аргументов ничего плохого я не мог

. script.sh > /dev/null 2>&1

но я блуждал, если есть лучший способ достичь моей цели.

Edit

Мое предложение об обходном пути не работает в случае вызова script exit, поэтому мне нужно уловить выход

#!/bin/sh

trap run_tests ERR EXIT

run_tests() {
   ...
}

. script.sh

Вызывается функция run_tests, но как только я перенаправляю вывод исходной команды, функции в script не анализируются и недоступны в обработчике trap

Это работает, но я получаю вывод script.sh:

#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
   function_defined_in_script_sh
}
. script.sh

Это не печатает вывод, но я получаю сообщение об ошибке, что функция не определена:

#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
   function_defined_in_script_sh
}
. script.sh | grep OUTPUT_THAT_DOES_NOT_EXISTS

Это не выводит вывод, а обработчик ловушки run_tests не вызывается вообще:

#!/bin/sh
trap run_tests ERR EXIT
run_tests() {
   function_defined_in_script_sh
}
. script.sh > /dev/null
4b9b3361

Ответ 1

В соответствии с разделом "Команды встроенной оболочки" bash manpage, . aka source принимает необязательный список аргументы, которые передаются в script. Вы можете использовать это, чтобы ввести опцию do-nothing. Например, script.sh может быть:

#!/bin/sh

foo() {
    echo foo $1
}

main() {
    foo 1
    foo 2
}

if [ "${1}" != "--source-only" ]; then
    main "${@}"
fi

и unit.sh могут быть:

#!/bin/bash

. ./script.sh --source-only

foo 3

Тогда script.sh будет вести себя нормально, а unit.sh будет иметь доступ ко всем функциям из script.sh, но не будет вызывать код main().

Обратите внимание, что дополнительные аргументы для source не находятся в POSIX, поэтому /bin/sh может не обрабатывать его - следовательно, #!/bin/bash в начале unit.sh.

Ответ 2

Поднял эту технику из Python, но концепция прекрасно работает в bash или любой другой оболочке...

Идея состоит в том, что мы превращаем раздел главного кода нашего script в функцию. Затем в самом конце script мы помещаем оператор if, который будет вызывать эту функцию только в том случае, если мы выполнили script, но не если мы ее получили. Затем мы явно вызываем функцию script() из наших "runtests" script, которая получила 'script' script и, следовательно, содержит все ее функции.

Это зависит от того, что, если мы выберем script, переменная среды bash -maintained $0, которая является именем выполняемого script, будет именем вызов (родительский) script (runtests в этом случае), а не источник script.

(Я переименовал script.sh только script, потому что .sh является избыточным и меня смущает.: -)

Ниже приведены два сценария. Некоторые примечания...

  • [email protected] оценивает все аргументы, переданные функции или script как отдельные строки. Если вместо этого мы использовали $*, все аргументы будут объединены в одну строку.
  • RUNNING="$(basename $0)" требуется, так как $0 всегда включает в себя по крайней мере, текущий префикс каталога, как в ./script.
  • Тест if [[ "$RUNNING" == "script" ]].... это волшебство, которое вызывает script, чтобы вызвать функцию script(), только если script был запущен напрямую из командной строки.

script

#!/bin/bash

foo ()    { echo "foo()"; }

bar ()    { echo "bar()"; }

script () {
  ARG1=$1
  ARG2=$2
  #
  echo "Running '$RUNNING'..."
  echo "script() - all args:  [email protected]"
  echo "script() -     ARG1:  $ARG1"
  echo "script() -     ARG2:  $ARG2"
  #
  foo
  bar
}

RUNNING="$(basename $0)"

if [[ "$RUNNING" == "script" ]]
then
  script "[email protected]"
fi

runtests

#!/bin/bash

source script 

# execute 'script' function in sourced file 'script'
script arg1 arg2 arg3

Ответ 3

Если вы используете Bash, аналогичное решение для подхода @andrewdotn (но без необходимости использования дополнительного флага или в зависимости от имени script) может быть выполнено с помощью массива BASH_SOURCE.

script.sh:

#!/bin/bash

foo () { ... }
bar () { ... }

main() {
    code
}

if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then
    main "[email protected]"
fi

run_tests.sh:

#!/bin/bash

. script.sh

# Unit tests