มีเหตุผลทางเทคนิคที่ถูกต้องตามกฎหมายที่จะต้องการวิธีการแก้ปัญหาทั่วไปของปัญหานามแฝงทุบตีที่ไม่ได้มีกลไกในการใช้การโต้แย้งตำแหน่งโดยพลการ เหตุผลหนึ่งคือหากคำสั่งที่คุณต้องการดำเนินการจะได้รับผลกระทบในทางลบจากการเปลี่ยนแปลงสภาพแวดล้อมที่เป็นผลมาจากการเรียกใช้ฟังก์ชัน ในกรณีอื่น ๆควรใช้ฟังก์ชั่น
สิ่งที่บังคับให้ฉันพยายามแก้ไขเมื่อเร็ว ๆ นี้คือฉันต้องการสร้างคำสั่งแบบย่อสำหรับการพิมพ์คำจำกัดความของตัวแปรและฟังก์ชั่น ดังนั้นฉันจึงเขียนฟังก์ชันบางอย่างเพื่อจุดประสงค์นั้น อย่างไรก็ตามมีตัวแปรบางอย่างที่เปลี่ยนแปลง (หรืออาจจะ) โดยการเรียกฟังก์ชันเอง ในหมู่พวกเขาคือ:
FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV
คำสั่งพื้นฐานที่ฉันใช้ (ในฟังก์ชั่น) เพื่อพิมพ์ตัวแปรแปรปรวน ในเอาต์พุตของฟอร์มโดยคำสั่ง set คือ:
sv () { set | grep --color=never -- "^$1=.*"; }
เช่น:
> V=voodoo
sv V
V=voodoo
ปัญหา: สิ่งนี้จะไม่พิมพ์คำจำกัดความของตัวแปรที่กล่าวถึงข้างต้นเนื่องจากอยู่ใน บริบทปัจจุบันเช่นหากอยู่ในพร้อมต์เชลล์แบบโต้ตอบ (หรือไม่ใช้ในการเรียกใช้ฟังก์ชันใด ๆ ) FUNCNAME จะไม่ถูกกำหนด แต่ฟังก์ชั่นของฉันบอกข้อมูลผิด:
> sv FUNCNAME
FUNCNAME=([0]="sv")
ทางออกหนึ่งที่ฉันคิดขึ้นได้ถูกกล่าวถึงโดยคนอื่นในโพสต์อื่น ๆ ในหัวข้อนี้ สำหรับคำสั่งเฉพาะนี้เพื่อพิมพ์ defns. และซึ่งต้องการเพียงหนึ่งอาร์กิวเมนต์ฉันทำสิ่งนี้:
alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'
ซึ่งให้เอาต์พุตที่ถูกต้อง (ไม่มี) และสถานะผลลัพธ์ (false):
> asv FUNCNAME
> echo $?
1
อย่างไรก็ตามฉันยังรู้สึกถูกบังคับให้ต้องหาวิธีแก้ปัญหาที่ใช้กับข้อโต้แย้งจำนวนมากโดยพลการ
วิธีแก้ปัญหาทั่วไปในการส่งผ่านอาร์กิวเมนต์โดยพลการไปยังคำสั่ง Bash Aliased:
# (I put this code in a file "alias-arg.sh"):
# cmd [arg1 ...] – an experimental command that optionally takes args,
# which are printed as "cmd(arg1 ...)"
#
# Also sets global variable "CMD_DONE" to "true".
#
cmd () { echo "cmd($@)"; declare -g CMD_DONE=true; }
# Now set up an alias "ac2" that passes to cmd two arguments placed
# after the alias, but passes them to cmd with their order reversed:
#
# ac2 cmd_arg2 cmd_arg1 – calls "cmd" as: "cmd cmd_arg1 cmd_arg2"
#
alias ac2='
# Set up cmd to be execed after f() finishes:
#
trap '\''cmd "${CMD_ARGV[1]}" "${CMD_ARGV[0]}"'\'' SIGUSR1;
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# (^This is the actually execed command^)
#
# f [arg0 arg1 ...] – acquires args and sets up trap to run cmd:
f () {
declare -ag CMD_ARGV=("$@"); # array to give args to cmd
kill -SIGUSR1 $$; # this causes cmd to be run
trap SIGUSR1; # unset the trap for SIGUSR1
unset CMD_ARGV; # clean up env...
unset f; # incl. this function!
};
f' # Finally, exec f, which will receive the args following "ac2".
เช่น:
> . alias-arg.sh
> ac2 one two
cmd(two one)
>
> # Check to see that command run via trap affects this environment:
> asv CMD_DONE
CMD_DONE=true
สิ่งที่ดีเกี่ยวกับการแก้ปัญหานี้คือเทคนิคพิเศษทั้งหมดที่ใช้ในการจัดการพารามิเตอร์ตำแหน่ง (อาร์กิวเมนต์) กับคำสั่งจะทำงานเมื่อเขียนคำสั่งที่ติดอยู่ ข้อแตกต่างเพียงอย่างเดียวคือต้องใช้ไวยากรณ์ของอาร์เรย์
เช่น,
หากคุณต้องการ "$ @" ให้ใช้ "$ {CMD_ARGV [@]}"
หากคุณต้องการ "$ #" ให้ใช้ "$ {# CMD_ARGV [@]}"
เป็นต้น