วิธีการกำหนดชื่อฟังก์ชั่นจากภายในฟังก์ชั่น


163

หากฉันมีสคริปต์ Bash เช่น:

#!/bin/bash

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

มีวิธีการทำเช่นนี้? สามารถใช้ในข้อความช่วยเหลือเช่น

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

เฉพาะในกรณีนี้สิ่งที่ฉันต้องการไม่ใช่$0ซึ่งเป็นชื่อไฟล์ของสคริปต์


2
ที่เกี่ยวข้อง: กรอบการเข้าสู่ระบบทุบตีที่ใช้FUNCNAMEอาร์เรย์และตัวแปรอื่น ๆ ทุบตี: github.com/codeforester/base/blob/master/lib/stdlib.sh ดูฟังก์ชั่นlog_debug_enterและlog_debug_leaveโดยเฉพาะอย่างยิ่ง
codeforester

คำตอบ:



79

จากคู่มืออ้างอิง Bash :

FUNCNAME

ตัวแปรอาร์เรย์ที่มีชื่อของฟังก์ชั่นเชลล์ทั้งหมดในปัจจุบันในการเรียกการเรียกใช้งาน องค์ประกอบที่มีดัชนี 0 เป็นชื่อของฟังก์ชั่นเปลือกที่กำลังดำเนินการใด ๆ ในปัจจุบัน องค์ประกอบด้านล่างสุด (องค์ประกอบที่มีดัชนีสูงสุด) คือ "หลัก" ตัวแปรนี้มีอยู่เฉพาะเมื่อมีการเรียกใช้ฟังก์ชันเชลล์ การกำหนดให้กับ FUNCNAME ไม่มีผลกระทบและส่งคืนสถานะข้อผิดพลาด หาก FUNCNAME ไม่ได้ตั้งค่ามันจะสูญเสียคุณสมบัติพิเศษแม้ว่าจะถูกรีเซ็ตในภายหลัง

ตัวแปรนี้สามารถใช้กับ BASH_LINENO และ BASH_SOURCE แต่ละองค์ประกอบของ FUNCNAME มีองค์ประกอบที่สอดคล้องกันใน BASH_LINENO และ BASH_SOURCE เพื่ออธิบายสายการโทร ตัวอย่างเช่น $ {FUNCNAME [$ i]} ถูกเรียกจากไฟล์ $ {BASH_SOURCE [$ i + 1]} ที่หมายเลขบรรทัด $ {BASH_LINENO [$ i]} ตัวเรียกในตัวแสดงสแต็กการโทรปัจจุบันโดยใช้ข้อมูลนี้

เมื่อเข้าถึง bash arrays โดยไม่มีดัชนีองค์ประกอบแรกของอาร์เรย์จะถูกส่งคืนดังนั้น$FUNCNAMEจะทำงานในกรณีง่าย ๆ เพื่อระบุชื่อของฟังก์ชันปัจจุบันทันที แต่ก็ยังมีฟังก์ชันอื่น ๆ ทั้งหมดใน call stack ตัวอย่างเช่น:

# 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

จะส่งออก:

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

6
ฉันยังไม่เข้าใจ เพิ่มทำไม[0]หากมันมีนัยโดยการเข้าถึงตัวแปรที่ไม่ได้ตกแต่ง?
Tom Hale

15
เพราะมันเป็นการหลอกลวงและไม่ทราบชนิดที่แท้จริงของตัวแปรใช่ไหม แน่นอนว่ามันไม่จำเป็นเสมอไป แต่เช่นเดียวกับ bash-isms อื่น ๆ มันเป็นการประชุมที่ขี้เกียจ ดีกว่าที่จะชัดเจนกว่าคลุมเครือ
bschlueter

36

ฉันใช้${FUNCNAME[0]}พิมพ์ชื่อฟังก์ชั่นปัจจุบัน


@bschlueter แต่เมื่อคุณอ้างอิงอาร์เรย์โดยไม่ถือว่ามันเหมือนกับอาร์เรย์ใน Bash มันก็แค่พิมพ์ค่าแรก ดังนั้นคำตอบที่ยอมรับนั้นไม่ถูกต้องอย่างไร
Alexej Magura

4
แน่นอนและมันสะดวก แต่ก็แย่มากสำหรับการบำรุงรักษาและทดสอบ อย่าขี้เกียจจงชัดเจน
bschlueter

1

ตัวอย่างอื่น:

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

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

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

จะส่งออก:

begin main
foo fuction begins
foobar fuction begins
end main

-1

วิธีที่ง่ายที่สุดในการรับชื่อฟังก์ชัน (จากภายในฟังก์ชัน)

echo $0

โปรดหยุดการใช้###คำตอบที่ไม่เหมาะสม
Marcin Orlowski

@MarcinOrlowski คุณสบายดีไหม? ฟังดูเหมือนว่าคุณสามารถใช้กอดได้
jasonleonhard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.