ฉันได้พูดคุยเกี่ยวกับวิธีการด้านล่างวิธีการทำงานหลายต่อหลายครั้งก่อนหน้านี้ดังนั้นฉันจะไม่ทำมันอีกครั้ง ส่วนตัวรายการโปรดของตัวเองในหัวข้อที่มีที่นี่และที่นี่
หากคุณไม่สนใจที่จะอ่านว่า แต่ยังอยากรู้อยากเห็นเพียงแค่เข้าใจว่าที่นี่เอกสารที่แนบมากับฟังก์ชั่นของการประเมินผลสำหรับการขยายตัวของเปลือกก่อนที่จะเรียกใช้ฟังก์ชั่นและพวกเขาจะถูกสร้างขึ้นใหม่ในสถานะที่พวกเขาทุกครั้งที่เรียกใช้ฟังก์ชัน
ประกาศ
คุณแค่ต้องการฟังก์ชั่นที่ประกาศฟังก์ชั่นอื่น ๆ
_fn_init() { . /dev/fd/4 ; } 4<<INIT
${1}() { $(shift ; printf %s\\n "$@")
} 4<<-REQ 5<<-\\RESET
: \${_if_unset?shell will ERR and print this to stderr}
: \${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init $(printf "'%s' " "$@")
RESET
INIT
เรียกใช้มัน
นี่ผมโทรเมื่อจะประกาศให้ฉันฟังก์ชั่นที่เรียกว่า_fn_init
fn
set -vx
_fn_init fn \
'echo "this would be command 1"' \
'echo "$common_param"'
#OUTPUT#
+ _fn_init fn 'echo "this would be command 1"' 'echo "$common_param"'
shift ; printf %s\\n "$@"
++ shift
++ printf '%s\n' 'echo "this would be command 1"' 'echo "$common_param"'
printf "'%s' " "$@"
++ printf ''\''%s'\'' ' fn 'echo "this would be command 1"' 'echo "$common_param"'
#ALL OF THE ABOVE OCCURS BEFORE _fn_init RUNS#
#FIRST AND ONLY COMMAND ACTUALLY IN FUNCTION BODY BELOW#
+ . /dev/fd/4
#fn AFTER _fn_init .dot SOURCES IT#
fn() { echo "this would be command 1"
echo "$common_param"
} 4<<-REQ 5<<-\RESET
: ${_if_unset?shell will ERR and print this to stderr}
: ${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init 'fn' \
'echo "this would be command 1"' \
'echo "$common_param"'
RESET
ที่จำเป็น
ถ้าฉันต้องการเรียกใช้ฟังก์ชันนี้มันจะตายถ้าไม่_if_unset
ได้ตั้งค่าตัวแปรสภาพแวดล้อม
fn
#OUTPUT#
+ fn
/dev/fd/4: line 1: _if_unset: shell will ERR and print this to stderr
โปรดทราบคำสั่งของร่องรอยเปลือก - ไม่เพียง แต่fn
ล้มเหลวเมื่อเรียกเมื่อ_if_unset
ไม่มีการตั้งค่า แต่มันไม่เคยทำงานในสถานที่แรก นี่คือปัจจัยที่สำคัญที่สุดที่จะเข้าใจเมื่อทำงานกับการขยายเอกสารที่นี่ - พวกเขาจะต้องเกิดขึ้นก่อนเสมอเพราะพวกเขาเป็น<<input
สิ่งสุดท้าย
ข้อผิดพลาดมาจาก/dev/fd/4
เนื่องจากเชลล์พาเรนต์ประเมินอินพุตนั้นก่อนส่งมอบให้กับฟังก์ชัน มันเป็นวิธีที่ง่ายที่สุดและมีประสิทธิภาพมากที่สุดในการทดสอบสภาพแวดล้อมที่จำเป็น
อย่างไรก็ตามความล้มเหลวสามารถแก้ไขได้ง่าย
_if_unset=set fn
#OUTPUT#
+ _if_unset=set
+ fn
+ echo 'this would be command 1'
this would be command 1
+ echo 'REQ/RESET added to all funcs'
REQ/RESET added to all funcs
มีความยืดหยุ่น
ตัวแปรคือการประเมินเป็นค่าเริ่มต้นในการป้อนข้อมูลสำหรับฟังก์ชั่นทุกประกาศโดยcommon_param
_fn_init
แต่คุณค่านั้นสามารถเปลี่ยนแปลงได้กับสิ่งอื่นใดซึ่งจะได้รับเกียรติจากทุกฟังก์ชั่นที่ประกาศในทำนองเดียวกัน ฉันจะทิ้งร่องรอยเปลือกเอาไว้ตอนนี้เราจะไม่เข้าไปในอาณาเขตใด ๆ ที่ไม่ได้จดที่นี่หรืออะไรก็ตาม
set +vx
_fn_init 'fn' \
'echo "Hi! I am the first function."' \
'echo "$common_param"'
_fn_init 'fn2' \
'echo "This is another function."' \
'echo "$common_param"'
_if_unset=set ;
_if_unset
ดังกล่าวข้างต้นผมประกาศสองฟังก์ชั่นและการตั้งค่า ตอนนี้ก่อนที่จะเรียกฟังก์ชั่นทั้งสองฉันจะยกเลิกการตั้งค่าcommon_param
เพื่อให้คุณสามารถเห็นพวกเขาจะตั้งค่าตัวเองเมื่อฉันเรียกพวกเขา
unset common_param ; echo
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
REQ/RESET added to all funcs
This is another function.
REQ/RESET added to all funcs
และตอนนี้จากขอบเขตของผู้โทร:
echo $common_param
#OUTPUT#
REQ/RESET added to all funcs
แต่ตอนนี้ฉันต้องการให้มันเป็นอย่างอื่น:
common_param="Our common parameter is now something else entirely."
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
Our common parameter is now something else entirely.
This is another function.
Our common parameter is now something else entirely.
และถ้าฉัน_if_unset
ไม่ล้าง?
unset _if_unset ; echo
echo "fn:"
fn ; echo
echo "fn2:"
fn2 ; echo
#OUTPUT#
fn:
dash: 1: _if_unset: shell will ERR and print this to stderr
fn2:
dash: 1: _if_unset: shell will ERR and print this to stderr
RESET
หากคุณต้องการรีเซ็ตสถานะของฟังก์ชั่นในเวลาใด ๆ ก็สามารถทำได้อย่างง่ายดาย คุณต้องทำเท่านั้น (จากภายในฟังก์ชั่น):
. /dev/fd/5
ฉันบันทึกข้อโต้แย้งที่ใช้ในการประกาศฟังก์ชั่นเริ่มต้นใน5<<\RESET
file-descriptor ดังนั้นการ.dot
หาว่าในเชลล์เมื่อใดก็ตามจะทำซ้ำขั้นตอนที่ตั้งไว้ในตอนแรก มันง่ายมากจริง ๆ และพกพาได้อย่างสมบูรณ์ถ้าคุณยินดีที่จะมองข้ามความจริงที่ว่า POSIX ไม่ได้ระบุเส้นทางโหนดอุปกรณ์ตัวอธิบายไฟล์ (ซึ่งเป็นสิ่งจำเป็นสำหรับเชลล์.dot
)
คุณสามารถขยายพฤติกรรมนี้ได้อย่างง่ายดายและกำหนดค่าสถานะต่างๆสำหรับฟังก์ชันของคุณ
มากกว่า?
วิธีนี้แทบจะไม่ทำให้พื้นผิวมีรอยขีดข่วน ฉันมักจะใช้เทคนิคเหล่านี้เพื่อฝังฟังก์ชั่นตัวช่วยเล็ก ๆ ที่ประกาศได้ตลอดเวลาลงในอินพุตของฟังก์ชั่นหลัก - ตัวอย่างเช่นสำหรับตำแหน่งเพิ่มเติม$@
อาร์เรย์ที่ต้องการ อันที่จริง - อย่างที่ฉันเชื่อมันต้องเป็นอะไรที่ใกล้เคียงกับนี้มาก คุณสามารถเห็นได้ว่าโปรแกรมเหล่านั้นตั้งชื่อได้ง่ายมาก
ฉันยังชอบที่จะประกาศฟังก์ชั่นเครื่องกำเนิดไฟฟ้าที่รับประเภทที่ จำกัด ของพารามิเตอร์แล้วกำหนดเดียวที่ใช้งานหรือมิฉะนั้นขอบเขต จำกัด เตาฟังก์ชั่นตามสายของแลมบ์ดา - หรือฟังก์ชั่นในบรรทัด - ที่เพียงunset -f
's ตัวเองเมื่อ ตลอด คุณสามารถส่งผ่านฟังก์ชันเชลล์ได้