ฟังก์ชั่นการโทรประกาศด้านล่าง


15

เป็นไปได้ไหมที่จะเรียกฟังก์ชั่นที่ถูกประกาศด้านล่างด้วยการทุบตี?

ตัวอย่าง

if [ "$input" = "yes" ]; then
    YES_FUNCTION
elif [ "$input" = "no" ]; then
    NO_FUNCTION
else
    exit 0;
fi

YES_FUNCTION()
{
  .....
  .....
}

NO_FUNCTION()
{
  .....
  .....
}

คำตอบ:


37

อย่างที่คนอื่นพูดคุณไม่สามารถทำเช่นนั้นได้

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

เช่น

#!/bin/sh

main() {
    if [ "$1" = yes ]; then
        do_task_this
    else
        do_task_that
    fi
}

do_task_this() {
    ...
} 
do_task_that() {
    ...
} 

main "$@"; exit

เมื่อเราเรียกmainที่ท้ายไฟล์ฟังก์ชั่นทั้งหมดจะถูกกำหนดไว้แล้ว อย่างชัดเจนผ่าน"$@"การmainเป็นสิ่งจำเป็นที่จะทำให้อาร์กิวเมนต์บรรทัดคำสั่งของสคริปต์ที่มองเห็นได้ในการทำงาน

ความชัดเจนexitในบรรทัดเดียวกันกับการเรียกไปยัง main นั้นไม่ใช่ข้อบังคับ แต่สามารถใช้เพื่อป้องกันสคริปต์ที่กำลังรันไม่ให้เกิดความสับสนหากไฟล์สคริปต์ถูกแก้ไข หากไม่มีเชลล์จะพยายามอ่านคำสั่งต่อจากไฟล์สคริปต์หลังจากmainส่งคืน (ดูวิธีการอ่านเชลล์สคริปต์ทั้งหมดก่อนที่จะรันมัน? )


@ikkachu คิดว่ามันควรจะทำงาน .. ให้ฉันตรวจสอบ
msp9011

8
ด้วย Bash สคริปต์ฉันมักจะใช้[[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@"เพื่อเรียกใช้ฟังก์ชั่นหลักเพื่อให้ฉันสามารถส่งมันมาในสคริปต์อื่นโดยไม่ต้องMainดำเนินการ จากนั้นฉันสามารถใช้ฟังก์ชันหรือเขียนการทดสอบซ้ำเพื่อตรวจสอบได้
BlackJack

11
การมีmain "$@"; exit( exitในบรรทัดเดียวกันกับmain) ก็มีประโยชน์เช่นเดียวกับการป้องกันไฟล์ที่ถูกแก้ไขขณะที่ถูกตีความ
Stéphane Chazelas

2
@JoL สิ่งที่อ่านไม่ได้อ่านอีกครั้งและเชลล์จะต้องอ่านและแยกข้อความทั้งหมดของลูปก่อนที่จะเริ่มเรียกใช้ แต่หลังจากลูปส่งคืนแล้วจะดำเนินการอ่านจากไฟล์ที่เหลือที่ ตำแหน่งปัจจุบัน (และหากไฟล์ถูกแก้ไขมันจะทำให้เกิดปัญหาขึ้น) หากทุกอย่างอยู่ในฟังก์ชั่นเชลล์จำเป็นต้องอ่านทุกอย่างก่อนที่จะเริ่มทำอะไร (ยกเว้นการกำหนดฟังก์ชั่นเหล่านั้น) ถ้าเราใส่exitในบรรทัดเดียวกันในขณะที่mainเราตรวจสอบให้แน่ใจว่าเชลล์จะไม่อ่านอะไรอีกmainแล้ว
Stéphane Chazelas

1
@MontyHarder มันไม่สำคัญว่าถ้าคุณใช้main; exit, main; exit $?หรือmain <EOF>ในทุกกรณีรหัสทางออกของmainใช้เป็นรหัสทางออกของสคริปต์ exitจะเป็นเพียงเพื่อป้องกันไม่ให้สิ่งที่ได้รับ messed ขึ้นถ้ามีคนแก้ไขสคริปต์ในขณะที่มันทำงาน
ilkkachu

13

ไม่จำเป็นต้องมีฟังก์ชั่นในสภาพแวดล้อมของเชลล์ในเวลาที่เรียกใช้

"Shell Style Guide"ของ Google มีการแก้ไขสำหรับสิ่งนี้:

mainจำเป็นต้องใช้ฟังก์ชันที่เรียกใช้สำหรับสคริปต์ที่ยาวพอที่จะมีฟังก์ชันอื่นอย่างน้อยหนึ่งฟังก์ชัน

ในตอนท้ายสุดของสคริปต์หลังจากฟังก์ชั่นทั้งหมดคุณจะมีคำสั่งเพียงอย่างเดียว

main "$@"

สิ่งนี้จะเรียกใช้mainฟังก์ชันด้วยพารามิเตอร์อะไรก็ตามที่สคริปต์ได้รับ mainฟังก์ชั่นอาจจะอยู่ที่ด้านบนของสคริปต์ (คู่มือสไตล์กล่าวว่าจะนำมันที่ด้านล่าง แต่แล้วอีกครั้งมันบอกว่าหลายสิ่งหลายอย่าง)

เมื่อเชลล์เข้าสู่การmainเรียกใช้ฟังก์ชันทั้งหมดในสคริปต์จะถูกวิเคราะห์คำและสามารถเรียกใช้จากภายในmainฟังก์ชันได้


9

ไม่ต้องประกาศฟังก์ชั่นก่อนใช้งาน เชลล์สคริปต์อ่านทีละบรรทัดและดำเนินการตามบรรทัด; ดังนั้นจึงไม่มีฟังก์ชันใด ๆ จนกว่าจะมีการดำเนินการประกาศ


ของคุณถูกต้อง ปัญหาคือฉันมี 30+ ฟังก์ชั่นในสคริปต์ มันค่อนข้างยุ่งยากเมื่อเราอ่านโค้ด ในCความสะดวกสบาย
msp9011

3
คุณสามารถใส่การประกาศฟังก์ชั่นของคุณในไฟล์อื่นและแหล่งที่มามัน ( . yourfile)
Stephen Kitt

ใช่ฉันได้ลองแล้ว แต่ข้อกำหนดคือต้องมีสคริปต์เดียว
msp9011

@SivaPrasath ปัญหาอะไรกันแน่? เพียงแค่กำหนดฟังก์ชั่นทั้งหมดหรือแม้แต่ใส่รหัสหลักลงในฟังก์ชั่นจากนั้นบรรทัดสุดท้ายจะแสดงฟังก์ชันที่เรียกว่าและมีส่วนหลักของสคริปต์
BlackJack

@SivaPrasath ใน C คุณไม่มีifคำสั่งเปล่านอกฟังก์ชัน ฟังก์ชั่นไม่ได้มีการกำหนดไว้เมื่อคุณประกาศifฟังก์ชั่น -containing เพียงเมื่อคุณเรียกมัน
chepner

4

เชลล์ไม่มีแนวคิดของdeclaringฟังก์ชัน ดังนั้นคุณไม่สามารถประกาศล่วงหน้าได้

ดังนั้นคุณต้องมีการใช้ฟังก์ชั่นการอ่านโดยเชลล์ก่อนจึงจะสามารถเรียกใช้


4
เทคนิคบางหอย (ksh, zsh) มีฟังก์ชั่น autoloadingคุณลักษณะซึ่งอาจจะเห็นเป็นรูปแบบของบางประกาศ (ที่autoload fบอกทำงาน แต่ร่างของมันเป็นเพียงโหลดเมื่อภาวนาครั้งแรก) ที่ไม่ได้ใช้กับ OP ของbashแม้ว่า
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.