Вопрос

В настоящее время я выполняю несколько модульных тестов, которые выполняются из bash.Модульные тесты инициализируются, выполняются и очищаются в скрипте bash.Этот скрипт обычно содержит функции init(), execute() и cleanup().Но они не являются обязательными.Я бы хотел проверить, определены ли они или нет.

Я делал это ранее, используя grep и разделяя исходный код, но это казалось неправильным.Есть ли более элегантный способ сделать это?

Редактировать:Следующий фрагмент работает как по волшебству:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'shell function'
}
Это было полезно?

Решение

Я думаю, вы ищете команду "type".Он сообщит вам, является ли что-либо функцией, встроенной функцией, внешней командой или просто не определено.Пример:

$ LC_ALL=C type foo
bash: type: foo: not found

$ LC_ALL=C type ls
ls is aliased to `ls --color=auto'

$ which type

$ LC_ALL=C type type
type is a shell builtin

$ LC_ALL=C type -t rvm
function

$ if [ -n "$(LC_ALL=C type -t rvm)" ] && [ "$(LC_ALL=C type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi
rvm is a function

Другие советы

$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1

Если declare выполняется в 10 раз быстрее, чем test, это казалось бы очевидным ответом.

Редактировать:Ниже приведен -f опция с BASH излишня, не стесняйтесь ее исключить.Лично мне трудно вспомнить, какая опция что делает, поэтому я просто использую обе. -f показывает функции и -F показывает имена функций.

#!/bin/sh

function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

function_exists function_name && echo Exists || echo No such function

Опция объявления "-F" приводит к тому, что она возвращает только имя найденной функции, а не все содержимое.

Не должно быть никакого измеримого снижения производительности при использовании /dev/null, и если это вас так сильно беспокоит:

fname=`declare -f -F $1`
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

Или объедините то и другое для вашего собственного бессмысленного удовольствия.Они оба работают.

fname=`declare -f -F $1`
errorlevel=$?
(( ! errorlevel )) && echo Errorlevel says $1 exists     || echo Errorlevel says $1 does not exist
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

Заимствуя из других решений и комментариев, я пришел к этому:

fn_exists() {
  # appended double quote is an ugly trick to make sure we do get a string -- if $1 is not a known command, type does not output anything
  [ `type -t $1`"" == 'function' ]
}

Используется как ...

if ! fn_exists $FN; then
    echo "Hey, $FN does not exist ! Duh."
    exit 2
fi

Он проверяет, является ли данный аргумент функцией, и избегает перенаправлений и других действий grepping.

Копаюсь в старом посте ...но недавно я воспользовался этим и протестировал обе альтернативы, описанные в :

test_declare () {
    a () { echo 'a' ;}

    declare -f a > /dev/null
}

test_type () {
    a () { echo 'a' ;}
    type a | grep -q 'is a function'
}

echo 'declare'
time for i in $(seq 1 1000); do test_declare; done
echo 'type'
time for i in $(seq 1 100); do test_type; done

это породило :

real    0m0.064s
user    0m0.040s
sys     0m0.020s
type

real    0m2.769s
user    0m1.620s
sys     0m1.130s

объявлять - это чертовски быстро !

Это сводится к использованию 'declare' либо для проверки выходных данных, либо для кода выхода.

Стиль вывода:

isFunction() { [[ "$(declare -Ff "$1")" ]]; }

Использование:

isFunction some_name && echo yes || echo no

Однако, если память не подводит, перенаправление на null выполняется быстрее, чем подстановка выходных данных (кстати, ужасный и устаревший метод `cmd` следует исключить и вместо него использовать $(cmd).) И поскольку declare возвращает true / false, если найдено / не найдено, а функции возвращают код выхода последней команды в функции, поэтому явный возврат обычно не требуется, и поскольку проверка кода ошибки выполняется быстрее, чем проверка строкового значения (даже нулевой строки):

Стиль статуса выхода:

isFunction() { declare -Ff "$1" >/dev/null; }

Это, вероятно, самое краткое и безобидное, что вы можете получить.

Скорость тестирования различных решений

#!/bin/bash

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
    local var=$(type -t f)
    [[ "${var-}" = function ]]
}

post=
for j in 1 2; do
echo
echo 'declare -f' $post
time for i in $(seq 1 1000); do test_declare; done
echo
echo 'declare -F' $post
time for i in $(seq 1 1000); do test_declare2; done
echo
echo 'type with grep' $post
time for i in $(seq 1 1000); do test_type; done
echo
echo 'type with var' $post
time for i in $(seq 1 1000); do test_type2; done
unset -f f
post='(f unset)'
done

результаты, например:

объявить -f

реальный 0m0.037s пользователь 0m0.024s система 0m0.012s

объявить -F

реальный 0m0.030s пользователь 0m0.020s система 0m0.008s

введите с помощью grep

реальный 0m1.772s пользователь 0m0.084s система 0m0.340s

введите с помощью var

реальный 0m0.770s пользователь 0m0.096s система 0m0.160s

объявить -f (f не задано)

реальный 0m0.031s пользователь 0m0.028s система 0m0.000s

объявить -F (f не задано)

реальный 0m0.031s пользователь 0m0.020s система 0m0.008s

введите с помощью grep (f не задано)

реальный 0m1.859s пользователь 0m0.100s система 0m0.348s

введите с помощью var (f не задано)

реальный 0m0.683 s пользователь 0m0.092s система 0m0.160s

Итак declare -F f && echo function f exists. || echo function f does not exist. кажется, это лучшее решение.

fn_exists()
{
   [[ $(type -t $1) == function ]] && return 0
}

Обновить

isFunc () 
{ 
    [[ $(type -t $1) == function ]]
}

$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$

Это говорит вам, существует ли она, но не о том, что это функция

fn_exists()
{
  type $1 >/dev/null 2>&1;
}

Мне особенно понравилось решение от Grégory Joseph

Но я немного изменил его, чтобы преодолеть "уродливый трюк с двойными кавычками".:

function is_executable()
{
    typeset TYPE_RESULT="`type -t $1`"

    if [ "$TYPE_RESULT" == 'function' ]; then
        return 0
    else
        return 1
    fi
}

Из моего комментария к другому ответу (который я продолжаю пропускать, когда возвращаюсь на эту страницу)

$ fn_exists() { test x$(type -t $1) = xfunction; }
$ fn_exists func1 && echo yes || echo no
no
$ func1() { echo hi from func1; }
$ func1
hi from func1
$ fn_exists func1 && echo yes || echo no
yes

Я бы улучшил его до:

fn_exists()
{
    type $1 2>/dev/null | grep -q 'is a function'
}

И используйте это следующим образом:

fn_exists test_function
if [ $? -eq 0 ]; then
    echo 'Function exists!'
else
    echo 'Function does not exist...'
fi

Можно использовать 'type' без каких-либо внешних команд, но вам придется вызывать его дважды, поэтому он все равно работает примерно в два раза медленнее, чем версия 'declare':

test_function () {
        ! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1
}

К тому же это не работает в POSIX sh, так что это совершенно бесполезно, за исключением мелочей!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top