Cách xác định tên hàm từ bên trong hàm


163

Nếu tôi có một đoạn script Bash như:

#!/bin/bash

f() {
  # echo function name, "f" in this case
}

Có cách nào để làm điều này? Điều này có thể được sử dụng trong các thông báo trợ giúp như

printf "Usage: %s: blah blah blah \n" $(basename $0) >&2; 

Chỉ trong trường hợp này, điều tôi muốn không phải $0là tên tập tin.


2
Liên quan: Khung ghi nhật ký Bash sử dụng FUNCNAMEmảng và các biến Bash khác: github.com/codeforester/base/blob/master/lib/stdlib.sh . Xem các chức năng log_debug_enterlog_debug_leaveđặc biệt.
codeforester

Câu trả lời:


236

Bạn có thể sử dụng ${FUNCNAME[0]}trong bashđể có được tên hàm.


79

Từ tài liệu tham khảo Bash :

FUNCNAME

Một biến mảng chứa tên của tất cả các hàm shell hiện có trong ngăn xếp lệnh thực thi. Phần tử có chỉ số 0 là tên của bất kỳ hàm shell nào đang thực thi. Phần tử dưới cùng nhất (phần tử có chỉ số cao nhất) là "chính". Biến này chỉ tồn tại khi một hàm shell đang thực thi. Việc gán cho FUNCNAME không có hiệu lực và trả về trạng thái lỗi. Nếu FUNCNAME không được đặt, nó sẽ mất các thuộc tính đặc biệt, ngay cả khi sau đó được đặt lại.

Biến này có thể được sử dụng với BASH_LINENO và BASH_SOURCE. Mỗi phần tử của FUNCNAME có các phần tử tương ứng trong BASH_LINENO và BASH_SOURCE để mô tả ngăn xếp cuộc gọi. Chẳng hạn, $ {FUNCNAME [$ i]} đã được gọi từ tệp $ {BASH_SOURCE [$ i + 1]} tại số dòng $ {BASH_LINENO [$ i]}. Trình dựng cuộc gọi hiển thị ngăn xếp cuộc gọi hiện tại bằng cách sử dụng thông tin này.

Khi các mảng bash được truy cập mà không có chỉ mục, phần tử đầu tiên của mảng sẽ được trả về, do đó $FUNCNAMEsẽ hoạt động trong các trường hợp đơn giản để cung cấp tên của hàm hiện tại ngay lập tức, nhưng nó cũng chứa tất cả các hàm khác trong ngăn xếp cuộc gọi. Ví dụ:

# in a file "foobar"
function foo {
    echo foo
    echo "In function $FUNCNAME: FUNCNAME=${FUNCNAME[*]}" >&2
}

function foobar {
    echo "$(foo)bar"
    echo "In function $FUNCNAME: FUNCNAME=${FUNCNAME[*]}" >&2
}

foobar

Sẽ xuất:

$ bash foobar
In function foo: FUNCNAME=foo foobar main
foobar
In function foobar: FUNCNAME=foobar main

6
Tôi vẫn không hiểu. Tại sao thêm [0]nếu nó ngụ ý bằng cách truy cập biến không được yêu cầu?
Tom Hale

15
Bởi vì đó là lừa đảo và không biết gì về loại thực tế của biến? Chắc chắn, không phải lúc nào cũng cần thiết, nhưng giống như nhiều bash-isms khác, đó là một quy ước lười biếng. Tốt hơn là rõ ràng hơn mơ hồ.
bschlueter

36

Tôi sử dụng ${FUNCNAME[0]}để in tên chức năng hiện tại


@bschlueter nhưng khi bạn tham chiếu một mảng mà không coi nó như một mảng trong Bash, nó chỉ in giá trị đầu tiên; do đó, làm thế nào là câu trả lời được chấp nhận không chính xác?
Alexej Magura

4
Chắc chắn, và đó là thuận tiện, nhưng khủng khiếp để bảo trì và thử nghiệm. Đừng lười biếng, hãy rõ ràng.
bschlueter

1

Một vi dụ khac:

# in a file "foobar"
foo() {
    echo "$FUNCNAME fuction begins"
}

foobar() {
    echo "$FUNCNAME fuction begins"
}

echo 'begin main'
foo
foobar
echo 'end main'

Sẽ xuất:

begin main
foo fuction begins
foobar fuction begins
end main

-1

Cách đơn giản nhất để lấy tên hàm (từ bên trong hàm)

echo $0

Hãy ngừng lạm dụng ###trong câu trả lời của bạn.
Marcin Orleansowski

@MarcinOrlowski Bạn đang làm tốt chứ? Âm thanh như bạn có thể sử dụng một cái ôm.
jasonleonhard
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.