문제

현재 저는 bash에서 실행되는 몇 가지 단위 테스트를 수행하고 있습니다.단위 테스트는 bash 스크립트에서 초기화, 실행 및 정리됩니다.이 스크립트에는 일반적으로 init(),execute() 및 cleanup() 함수가 포함되어 있습니다.그러나 필수사항은 아닙니다.정의되어 있는지 여부를 테스트하고 싶습니다.

이전에 소스를 greping하고 sed하여 이 작업을 수행했지만 잘못된 것 같습니다.이를 수행하는 더 우아한 방법이 있습니까?

편집하다:다음 스니플릿은 매력처럼 작동합니다.

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가 test보다 10배 빠르다면 이것이 분명한 대답처럼 보일 것입니다.

편집하다:아래에서는 -f BASH에서는 이 옵션이 불필요하므로 자유롭게 남겨두시기 바랍니다.개인적으로 어떤 옵션이 어떤 기능을 하는지 기억하기 어렵기 때문에 둘 다 사용합니다. -에프 기능을 보여주고, -에프 함수 이름을 보여줍니다.

#!/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

주어진 인수가 함수인지 확인하고 리디렉션 및 기타 파악을 방지합니다.

오래된 게시물을 정리 중입니다...그러나 나는 최근에 이것을 사용했고 다음과 같이 설명된 두 가지 대안을 모두 테스트했습니다.

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

선언이 엄청나게 빨라졌습니다!

결국 출력이나 종료 코드를 확인하기 위해 '선언'을 사용하는 것으로 요약됩니다.

출력 스타일:

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

용법:

isFunction some_name && echo yes || echo no

그러나 메모리가 제공되면 null로 리디렉션하는 것이 출력 대체보다 빠릅니다(즉, 끔찍하고 오래된 `cmd` 메서드는 제거되고 대신 $(cmd)를 사용해야 합니다.) 그리고 선언이 발견되면 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

Real 0M0.037S 사용자 0M0.024S SYS 0M0.012S

선언 -F

Real 0M0.030S 사용자 0m0.020S SYS 0M0.008S

grep으로 입력

Real 0M1.772S 사용자 0M0.084S SYS 0M0.340S

var로 입력

Real 0M0.770S 사용자 0M0.096S SYS 0M0.160S

-f 선언(f 설정 해제)

Real 0M0.031S 사용자 0M0.028S SYS 0M0.000S

선언 -F (f 설정 해제)

Real 0M0.031S 사용자 0M0.020S SYS 0M0.008S

grep으로 입력(f ​​unset)

Real 0M1.859S 사용자 0M0.100S SYS 0M0.348S

var로 입력(f ​​unset)

Real 0M0.683S 사용자 0M0.092S SYS 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;
}

나는 특히 다음의 솔루션을 좋아했습니다. 그레고리 조셉

그러나 "큰따옴표 추악한 트릭"을 극복하기 위해 약간 수정했습니다.

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