it-swarm-vi.tech

Xác định nếu một hàm tồn tại trong bash

Hiện tại tôi đang thực hiện một số bài kiểm tra đơn vị được thực hiện từ bash. Các bài kiểm tra đơn vị được khởi tạo, thực hiện và dọn sạch trong một tập lệnh bash. Tập lệnh này thường chứa các hàm init (), exec () và cleanup (). Nhưng chúng không bắt buộc. Tôi muốn kiểm tra xem chúng có hoặc không được xác định.

Tôi đã làm điều này trước đây bằng cách gre và sed nguồn, nhưng nó có vẻ sai. Có một cách thanh lịch hơn để làm điều này?

Chỉnh sửa: Sniplet sau hoạt động như một bùa mê:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'Shell function'
}
163
terminus

Tôi nghĩ rằng bạn đang tìm kiếm lệnh 'loại'. Nó sẽ cho bạn biết liệu một cái gì đó là một chức năng, chức năng tích hợp, lệnh bên ngoài hoặc chỉ không được xác định. Thí dụ:

$ 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
175
JBB
$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1
69
Allan Wind

Nếu khai báo nhanh hơn 10 lần so với thử nghiệm, đây có vẻ là câu trả lời rõ ràng.

Chỉnh sửa: Bên dưới, tùy chọn -f là không cần thiết với BASH, vui lòng bỏ qua. Cá nhân, tôi gặp khó khăn trong việc ghi nhớ tùy chọn nào, vì vậy tôi chỉ sử dụng cả hai. - f hiển thị các hàm và - F hiển thị tên hàm.

#!/bin/sh

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

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

Tùy chọn "-F" để khai báo khiến nó chỉ trả về tên của hàm tìm thấy, thay vì toàn bộ nội dung.

Không nên có bất kỳ hình phạt hiệu suất có thể đo lường nào khi sử dụng/dev/null và nếu điều đó làm bạn lo lắng nhiều như vậy:

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

Hoặc kết hợp cả hai, để tận hưởng vô nghĩa của riêng bạn. Cả hai đều làm việc.

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
36
Orwellophile

Mượn từ các giải pháp và ý kiến ​​khác, tôi đã đưa ra điều này:

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' ]
}

Được dung như ...

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

Nó kiểm tra xem đối số đã cho có phải là một hàm hay không và tránh các chuyển hướng và grepping khác.

18
Grégory Joseph

Nạo vét một bài viết cũ ... nhưng gần đây tôi đã sử dụng điều này và đã thử nghiệm cả hai phương án được mô tả với:

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

điều này tạo ra:

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

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

tuyên bố là một helluvalot nhanh hơn!

9
jonathanserafini

Nó sử dụng 'khai báo' để kiểm tra mã đầu ra hoặc mã thoát.

Kiểu đầu ra:

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

Sử dụng:

isFunction some_name && echo yes || echo no

Tuy nhiên, nếu bộ nhớ phục vụ, chuyển hướng đến null nhanh hơn thay thế đầu ra (nói về, phương thức `cmd` khủng khiếp và lỗi thời nên được sử dụng và thay vào đó sử dụng $ (cmd).) Và vì khai báo trả về true/false nếu tìm thấy/không tìm thấy và các hàm trả về mã thoát của lệnh cuối cùng trong hàm nên thường không cần trả về rõ ràng và vì việc kiểm tra mã lỗi nhanh hơn kiểm tra giá trị chuỗi (thậm chí là chuỗi null):

Thoát trạng thái kiểu:

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

Đó có lẽ là về cô đọng và lành tính như bạn có thể nhận được.

6
Scott

Tốc độ thử nghiệm của các giải pháp khác nhau

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

đầu ra, ví dụ:

tuyên bố -f

người dùng thực 0m0.037s 0m0.024s sys 0m0.012s

tuyên bố -F

người dùng thực 0m0.030s 0m0.020s sys 0m0.008s

gõ với grep

người dùng thực 0m1.772s 0m0.084s sys 0m0.340s

gõ với var

người dùng thực 0m0.770s 0m0.096s sys 0m0.160s

khai báo -f (f unset)

người dùng thực 0m0.031s 0m0.028s sys 0m0.000s

khai báo -F (f unset)

người dùng thực 0m0.031s 0m0.020s sys 0m0.008s

gõ bằng grep (f unset)

người dùng thực 0m1.859s 0m0.100s sys 0m0.348s

gõ với var (f unset)

người dùng thực 0m0.683s 0m0.092s sys 0m0.160s

Vì vậy, declare -F f && echo function f exists. || echo function f does not exist. dường như là giải pháp tốt nhất.

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

cập nhật

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

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

Tôi đặc biệt thích giải pháp từ Grégory Joseph

Nhưng tôi đã sửa đổi nó một chút để vượt qua "cú đúp xấu xí":

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

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

Điều này cho bạn biết nếu nó tồn tại, nhưng đó không phải là một chức năng

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

Từ nhận xét của tôi về một câu trả lời khác (mà tôi vẫn thiếu khi quay lại trang này)

$ 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
2
qneill

Tôi sẽ cải thiện nó để:

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

Và sử dụng nó như thế này:

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

Có thể sử dụng 'loại' mà không cần bất kỳ lệnh bên ngoài nào, nhưng bạn phải gọi nó hai lần, do đó, nó vẫn kết thúc chậm khoảng hai lần so với phiên bản 'khai báo':

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

Thêm vào đó, điều này không hoạt động trong POSIX sh, vì vậy nó hoàn toàn vô giá trị trừ những chuyện vặt vãnh!

0
Noah Spurrier