เชลล์เนมสเปซ


10

มีวิธีsourceเชลล์สคริปต์ในเนมสเปซหรือไม่โดยเฉพาะอย่างยิ่งสคริปต์เชลล์ทุบตี แต่ฉันจะดูเชลล์อื่น ๆ หากมีคุณลักษณะนี้และทุบตีไม่ได้

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

หากมีวิธีการแก้ปัญหาที่ฉันสามารถ namespace ในsourceเวลา ( NodeJSสไตล์) นั่นจะดีที่สุด

รหัสตัวอย่าง:

$ echo 'hi(){ echo Hello, world; }' > english.sh
$ echo 'hi(){ echo Ahoj, světe; }' > czech.sh
$ . english.sh
$ hi
 #=> Hello, world
$ . czech.sh #bash doesn't even warn me that `hi` is being overwritten here
$ hi
 #=> Ahoj, světe
#Can't use the English hi now
#And sourcing the appropriate file before each invocation wouldn't be very efficient 

1
ขอขอบคุณสำหรับการชี้แจง. ฉันคาดหวังว่าคำตอบนั้นเป็นลบ กระบวนทัศน์การเขียนโปรแกรมเปลือกปกติคือเมื่อคุณต้องการที่จะเปลี่ยนแปลงแยกคุณทำมันใน subshell ( easiest thing ever )ซึ่งสร้างหนึ่งเป็นเพียงเกี่ยวกับ แต่นั่นไม่ใช่สิ่งที่คุณต้องการ ฉันเดาว่าคุณสามารถทำได้( stuff in subshell; exec env ) | sed 's/^/namespace_/'และevalผลลัพธ์ในเปลือกหลัก แต่ก็น่ารังเกียจ
Celada

3
ใช่. ksh93ได้รับ เนมสเปซเป็นพื้นฐานสำหรับมัน - และทุกประเภทของชื่อ(ซึ่งก็ยังพิมพ์ได้)รองรับการกำหนดเนมสเปซ นอกจากนี้ยังได้เร็วขึ้นมากในทางปฏิบัติทุกประการกว่าbashโดยวิธีการ
mikeserv

@mikeserv ขอบคุณถ้าคุณเพิ่มเป็นคำตอบด้วยตัวอย่างรหัสที่แสดงให้เห็นถึงการทำงานฉันจะยอมรับมัน
PSkocik

@michas ฉันจะต้องใช้สัญลักษณ์ฟังก์ชั่น namespace และนามแฝงด้วย env | sed ...จะทำงานกับตัวแปรได้ฉันสามารถทำได้setเพื่อรับฟังก์ชั่น แต่การค้นหาและแทนที่จะเป็นปัญหา - ฟังก์ชั่นสามารถโทรหากันและคุณต้องเปลี่ยนการเรียกใช้ไขว้ทั้งหมดด้วย cross invocations แต่ไม่ต้องแทนที่ คำเดียวกันในที่ใดก็ได้ในรหัสนิยามฟังก์ชันซึ่งไม่มีการเรียก สำหรับสิ่งที่คุณต้องมีเครื่องมือแยกวิเคราะห์ bash ไม่ใช่แค่ regex และมันจะทำงานได้ตราบใดที่ฟังก์ชั่นไม่ได้โทรหากันผ่านทาง eval
PSkocik

คำตอบ:


11

จากman kshบนระบบที่ksh93ติดตั้ง ...

  • ช่องว่างชื่อ
    • คำสั่งและฟังก์ชั่นที่มีการดำเนินการเป็นส่วนหนึ่งของรายการที่คำสั่งที่ตัวแปรแก้ไขหรือสร้างใหม่สร้างตัวแปรใหม่ที่มีชื่อเป็นชื่อของพื้นที่ชื่อตามที่กำหนดโดยระบุนำหน้าด้วยnamespace เมื่อตัวแปรที่มีชื่อเป็นชื่อถูกอ้างอิงก็จะค้นหาครั้งแรกสำหรับการใช้..identifier.name
    • ในทำนองเดียวกันฟังก์ชั่นที่กำหนดโดยคำสั่งในรายการ namespace .จะถูกสร้างขึ้นโดยใช้ชื่อพื้นที่ชื่อนำหน้าด้วย
    • เมื่อรายการของคำสั่ง namespace ที่มีคำสั่งชื่อตัวแปรและฟังก์ชั่นที่สร้างขึ้นประกอบด้วยตัวแปรหรือฟังก์ชั่นชื่อนำหน้าด้วยรายการของตัวระบุแต่ละนำหน้าด้วยnamespace .นอกพื้นที่ชื่อตัวแปรหรือฟังก์ชั่นที่สร้างขึ้นภายในพื้นที่ชื่อสามารถอ้างอิงได้โดยนำหน้าด้วยชื่อพื้นที่ชื่อ
    • โดยค่าเริ่มต้นตัวแปรที่จ้องมองด้วย.shจะอยู่ในshพื้นที่ชื่อ

และเพื่อสาธิตนี่คือแนวคิดที่ใช้กับเนมสเปซที่จัดเตรียมไว้ตามค่าเริ่มต้นสำหรับตัวแปรเชลล์ปกติทุกตัวที่กำหนดไว้ในksh93เชลล์ ในตัวอย่างต่อไปนี้ฉันจะกำหนดdisciplineฟังก์ชั่นที่จะทำหน้าที่เป็น.getวิธีการที่กำหนดสำหรับ$PS1ตัวแปรเชลล์ ตัวแปรเปลือกทุกพื้นได้รับ namespace ของตัวเองด้วยอย่างน้อยเริ่มต้นget, set, appendและunsetวิธีการ หลังจากกำหนดฟังก์ชั่นต่อไปนี้ทุกครั้งที่$PS1มีการอ้างอิงตัวแปรในเชลล์เอาต์พุตของdateจะถูกวาดที่ด้านบนของหน้าจอ ...

function PS1.get {
    printf "\0337\33[H\33[K%s\0338" "${ date; }"
}

(โปรดสังเกตว่าการขาด()subshell ในการทดแทนคำสั่งด้านบน)

เทคนิคnamespacesและสาขาวิชาไม่ได้ว่าสิ่งเดียวกัน(เพราะสาขาวิชาที่สามารถกำหนดที่จะใช้อย่างใดอย่างหนึ่งทั่วโลกหรือในท้องถิ่นเพื่อเฉพาะnamespace )ksh93แต่พวกเขามีทั้งส่วนหนึ่งและพัสดุเพื่อแนวความคิดของชนิดข้อมูลเปลือกซึ่งเป็นพื้นฐานในการ

ในการพูดถึงตัวอย่างเฉพาะของคุณ:

echo 'function hi { echo Ahoj, světe\!;  }' >  czech.ksh
echo 'function hi { echo Hello, World\!; }' >english.ksh
namespace english { . ./english.ksh; }
namespace czech   { . ./czech.ksh;   }
.english.hi; .czech.hi

Hello, World!
Ahoj, světe!

...หรือ...

for ns in czech english
do  ".$ns.hi"
done

Ahoj, světe!
Hello, World!

@PSkocik - ทำไมคุณไม่แก้ไขสิ่งehojของฉัน ฉันสาบานได้ว่าเป็นสิ่งที่กล่าวไว้ก่อนหน้านี้ ... ขอโทษด้วย ฉันจะไม่ยอมรับคำตอบที่เขียนโดยคนที่ไม่สนใจสะกดคำที่ฉันใช้ในคำถามอย่างถูกต้อง ... อย่างสุจริตแม้ว่าฉันคิดว่าฉันจำได้แค่คัดลอก / วาง jt ... อืม ...
mikeserv

2

ฉันได้เขียนฟังก์ชั่น POSIX เปลือกซึ่งอาจนำมาใช้เพื่อท้องถิ่นใน namespace builtin เปลือกหรือฟังก์ชั่นในการใด ๆksh93, dash, mkshหรือ(ชื่อเฉพาะเพราะผมได้รับการยืนยันโดยส่วนตัวแล้วก็ไปทำงานในทุกเหล่านี้)bash จากกระสุนที่ฉันทดสอบมันล้มเหลวในการตอบสนองความคาดหวังของฉันyashเท่านั้นและฉันไม่เคยคาดหวังว่ามันจะทำงานได้zshเลย poshผมไม่ได้ทดสอบ ฉันหมดหวังไประยะposhหนึ่งแล้วและยังไม่ได้ติดตั้งในช่วงเวลาหนึ่ง อาจใช้งานได้ในposh...

ฉันบอกว่ามันเป็น POSIX เพราะจากการอ่านข้อกำหนดฉันใช้ประโยชน์จากพฤติกรรมที่ระบุของยูทิลิตี้พื้นฐาน แต่เป็นที่ยอมรับว่าข้อกำหนดนั้นไม่ชัดเจนในเรื่องนี้และอย่างน้อยหนึ่งคนก็ไม่เห็นด้วยกับฉัน โดยทั่วไปฉันมีความไม่เห็นด้วยกับสิ่งนี้ในที่สุดฉันก็พบว่ามีข้อผิดพลาดเป็นของตัวเองและฉันอาจผิดในครั้งนี้เกี่ยวกับข้อกำหนดเช่นกัน แต่เมื่อฉันถามเขาต่อไปเขาไม่ตอบกลับ

อย่างที่ฉันบอกไปว่ามันใช้งานได้กับเปลือกหอยดังกล่าวอย่างแน่นอนและใช้งานได้จริงตามวิธีต่อไปนี้:

some_fn(){ x=3; echo "$x"; }
x=
x=local command eval some_fn
echo "${x:-empty}"

3
empty

commandคำสั่งระบุเป็นสาธารณูปโภคที่มีอยู่โดยทั่วไปและเป็นหนึ่งในก่อน$PATH'd builtins หนึ่งในฟังก์ชั่นที่ระบุคือการห่อยูทิลิตี้บิวอินพิเศษในสภาพแวดล้อมของตัวเองเมื่อเรียกพวกเขาและ ...

{       sh -c ' x=5 set --; echo "$x"
                x=6 command set --; echo "$x"
                exec <"";  echo uh_oh'
        sh -c ' command exec <""; echo still here'
}

5
5
sh: 3: cannot open : No such file
sh: 1: cannot open : No such file
still here

... พฤติกรรมของการมอบหมายทั้งสองบรรทัดคำสั่งด้านบนนั้นถูกต้องตามข้อมูลจำเพาะ พฤติกรรมของเงื่อนไขข้อผิดพลาดทั้งสองก็ถูกต้องเช่นกันและในความเป็นจริงแล้วมีการทำซ้ำเกือบทั้งหมดจากข้อมูลจำเพาะ การกำหนดคำนำหน้าให้กับบรรทัดคำสั่งของฟังก์ชั่นหรือบิวด์อินพิเศษจะถูกระบุเพื่อส่งผลกระทบต่อสภาพแวดล้อมของเชลล์ในปัจจุบัน ในทำนองเดียวกันข้อผิดพลาดในการเปลี่ยนเส้นทางจะถูกระบุว่าร้ายแรงเมื่อชี้ไปที่ข้อใดข้อหนึ่ง commandถูกระบุเพื่อระงับการดูแลพิเศษของ buildins พิเศษในกรณีเหล่านั้นและกรณีการเปลี่ยนทิศทางถูกแสดงโดยตัวอย่างจริงในสเปค

ปกติบิวด์อินcommandจะถูกระบุให้ทำงานในสภาพแวดล้อม subshell - ซึ่งไม่ได้แปลว่ากระบวนการอื่นเพียงอย่างเดียวนั่นก็คือมันควรจะแยกไม่ออกจากพื้นฐาน ผลลัพธ์ของการเรียกบิวด์ปกติควรคล้ายกับสิ่งที่อาจได้รับจาก$PATHคำสั่ง 'd ที่มีความสามารถคล้ายกัน และดังนั้น ...

na=not_applicable_to_read
na= read var1 na na var2 <<"" ; echo "$var1" "$na" "$var2"
word1 other words word2

word1 not_applicable_to_read word2

แต่commandคำสั่งไม่สามารถเรียกใช้ฟังก์ชันเชลล์ได้ดังนั้นจึงไม่สามารถใช้เพื่อแสดงผลการบําบัดแบบพิเศษที่มันสามารถสร้างได้ในตัวปกติ นั่นก็สเป็คเช่นกัน ในความเป็นจริง spec ระบุว่ายูทิลิตี้หลักของcommandคือคุณสามารถใช้มันภายในฟังก์ชั่นเปลือกเสื้อคลุมที่มีชื่อสำหรับคำสั่งอื่นที่จะเรียกคำสั่งอื่นที่ไม่มีการเรียกซ้ำตัวเองเพราะมันจะไม่เรียกฟังก์ชั่น แบบนี้:

cd(){ command cd -- "$1"; }

หากคุณไม่ได้ใช้งานที่commandนั่นcdฟังก์ชั่นนี้ก็เกือบจะแน่นอนสำหรับการเรียกซ้ำตัวเอง

แต่เป็น builtin ปกติซึ่งสามารถเรียก builtins พิเศษcommandสามารถทำได้ในสภาพแวดล้อม subshell ดังนั้นในขณะที่ปัจจุบันเปลือกรัฐกำหนดไว้ภายในอาจติดเปลือกปัจจุบัน - แน่นอนread's $var1และ$var2ได้ - อย่างน้อยผลของการกำหนดบรรทัดคำสั่งอาจจะไม่ควร ...

คำสั่งง่ายๆ

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

ตอนนี้commandความสามารถในการเป็นทั้ง builtin ปกติและการเรียก builtins พิเศษโดยตรงเป็นเพียงช่องโหว่ที่ไม่คาดคิดเกี่ยวกับ command-line ที่กำหนดฉันไม่ทราบ แต่ฉันรู้ว่าอย่างน้อยสี่ shells แล้ว กล่าวถึงเกียรติcommandnamespace

และถึงแม้ว่าcommandจะไม่สามารถเรียกใช้ฟังก์ชันเชลล์ได้โดยตรง แต่สามารถเรียกได้evalตามที่แสดงและสามารถทำได้โดยอ้อม ดังนั้นฉันจึงสร้างเสื้อคลุมเนมสเปซบนแนวคิดนี้ ใช้รายการของการโต้แย้งเช่น:

ns any=assignments or otherwise=valid names which are not a command then all of its args

... ยกเว้นว่าคำดังกล่าวข้างต้นได้รับการยอมรับว่าเป็นหนึ่งในเพียงถ้ามันสามารถจะพบกับที่ว่างเปล่าcommand $PATHนอกจากนี้ในประเทศที่กำหนดขอบเขตตัวแปรเปลือกชื่อในบรรทัดคำสั่งก็ยังประเทศที่ขอบเขตตัวแปรทั้งหมดที่มีชื่อเดียวกรณีที่ต่ำกว่าตัวอักษรและรายชื่อของคนที่มาตรฐานอื่น ๆ เช่น$PS3, $PS4, $OPTARG, $OPTIND, $IFS, $PATH, $PWD, $OLDPWDและคนอื่น ๆ

และใช่โดยท้องถิ่นกำหนดขอบเขต$PWDและ$OLDPWDตัวแปรและหลังจากนั้นอย่างชัดเจนcdไอเอ็นจีไป$OLDPWDและ$PWDก็สามารถขอบเขตค่อนข้างน่าเชื่อถือไดเรกทอรีการทำงานปัจจุบันได้เป็นอย่างดี สิ่งนี้ไม่รับประกันแม้ว่าจะพยายามอย่างหนัก จะยังคงบ่งชี้สำหรับและเมื่อผลตอบแทนเป้าหมายห่อของมันไม่7<. cd -P /dev/fd/7/หากไดเรกทอรีการทำงานปัจจุบันได้รับการunlink()'ในระหว่างกาลอย่างน้อยก็ควรจัดการอย่างน้อยเปลี่ยนกลับเป็น แต่จะปล่อยข้อผิดพลาดน่าเกลียดในกรณีที่แม้ว่า และเพราะมันยังคงบ่งผมไม่คิดว่าเคอร์เนลสติจะช่วยให้อุปกรณ์รากของมันที่จะเดินเท้าอย่างใดอย่างหนึ่ง(???)

นอกจากนี้ยังกำหนดขอบเขตตัวเลือกเชลล์ในเครื่องและกู้คืนสิ่งเหล่านี้กลับสู่สถานะที่พบเมื่อการคืนค่ายูทิลิตี้ที่ห่อหุ้ม มันถือว่าเป็นพิเศษในการที่จะรักษาสำเนาอยู่ในขอบเขตของตัวเองซึ่งตอนแรกกำหนดมูลค่าของการ$OPTS $-หลังจากจัดการกับการมอบหมายทั้งหมดในบรรทัดคำสั่งแล้วมันจะทำset -$OPTSก่อนที่จะเรียกใช้เป้าหมายการตัดคำ ด้วยวิธีนี้หากคุณกำหนด-$OPTSในบรรทัดคำสั่งคุณสามารถกำหนดตัวเลือกเชลล์ของเป้าหมายการตัดคำของคุณ เมื่อเป้าหมายกลับมาก็จะset +$- -$OPTSมีสำเนาของตัวเอง$OPTS (ซึ่งไม่ได้รับผลกระทบจากการกำหนดบรรทัดคำสั่ง)และเรียกคืนทั้งหมดกลับสู่สถานะดั้งเดิม

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

ที่จะทำทุกสิ่งที่มันต้องผ่านไปสามevalลึก ก่อนอื่นมันจะล้อมตัวเองในขอบเขตของท้องถิ่นจากนั้นภายในจะอ่านในอาร์กิวเมนต์ตรวจสอบพวกเขาสำหรับชื่อเชลล์ที่ถูกต้องและออกจากข้อผิดพลาดหากพบว่ามันไม่ได้ หากข้อโต้แย้งทั้งหมดถูกต้องและในที่สุดก็เป็นหนึ่งในสาเหตุcommand -v "$1"ที่จะกลับจริง(การเรียกคืน: $PATHว่างเปล่าที่จุดนี้)มันจะevalกำหนดบรรทัดคำสั่งและส่งออกข้อโต้แย้งที่เหลืออยู่ทั้งหมดไปยังเป้าหมายห่อ(แม้ว่ามันจะไม่สนใจกรณีพิเศษสำหรับns- เพราะ wouldn ว่า 'T จะมีประโยชน์มากและสามevalลึก s เป็นมากกว่าเพียงพอลึก)

มันใช้งานได้ดังนี้:

case $- in (*c*) ... # because set -c doesnt work
esac
_PATH=$PATH PATH= OPTS=$- some=vars \
    command eval LOCALS=${list_of_LOCALS}'
        for a do  i=$((i+1))          # arg ref
              if  [ "$a" != ns ]  &&  # ns ns would be silly
                  command -v "$a" &&
              !   alias "$a"          # aliases are hard to run quoted
        then  eval " PATH=\$_PATH OTHERS=$DEFAULTS $v \
                     command eval '\''
                             shift $((i-1))         # leave only tgt in @
                             case $OPTS in (*different*)
                                  set \"-\${OPTS}\" # init shell opts 
                             esac
                             \"\$@\"                # run simple command
                             set +$- -$OPTS "$?"    # save return, restore opts
                     '\''"
              cd -P /dev/fd/7/        # go whence we came
              return  "$(($??$?:$1))" # return >0 for cd else $1
        else  case $a in (*badname*) : get mad;;
              # rest of arg sa${v}es
              esac
        fi;   done
    ' 7<.

มีบางอย่างที่เปลี่ยนเส้นทางอื่น ๆ และและการทดสอบที่แปลกไม่กี่จะทำอย่างไรกับวิธีการที่เปลือกบางใส่อยู่cใน$-นั้นปฏิเสธที่จะยอมรับว่ามันเป็นตัวเลือกให้กับset (???)แต่ทั้งหมดขึ้นอยู่กับตนและใช้เป็นหลักเพียงเพื่อประหยัดจากเปล่ง ผลลัพธ์ที่ไม่ต้องการและคล้ายกันในกรณีขอบ และนั่นคือวิธีการทำงาน มันสามารถทำสิ่งเหล่านั้นเพราะมันตั้งค่าขอบเขตของตัวเองก่อนที่จะเรียกยูทิลิตี้ที่ถูกห่อหุ้มไว้ในที่ซ้อนกัน

มันยาวเพราะฉันพยายามระวังให้มากที่นี่ - สามevalsอย่างยาก แต่ด้วยสิ่งนี้คุณสามารถทำได้:

ns X=local . /dev/fd/0 <<""; echo "$X" "$Y"
X=still_local
Y=global
echo "$X" "$Y"

still_local global
 global

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

ชอบ:

ns var1=something var2= eval ' printf "%-10s%-10s%-10s%s\n" $LOCALS '

... ซึ่งปลอดภัยอย่างสมบูรณ์ - $IFSได้รับการทำให้บริสุทธิ์เป็นค่าเริ่มต้นและมีเพียงชื่อเชลล์ที่ถูกต้องเท่านั้นที่จะทำให้เป็นชื่อ$LOCALSเว้นแต่คุณจะตั้งค่าตัวเองในบรรทัดคำสั่ง และแม้ว่าอาจจะมีตัวละครกลมในตัวแปรแยกคุณสามารถตั้งค่าOPTS=fในบรรทัดคำสั่งเช่นกันสำหรับยูทิลิตี้ที่ห่อหุ้มเพื่อห้ามการขยายตัวของพวกเขา ไม่ว่ากรณีใด ๆ:

LOCALS    ARG0      ARGC      HOME
IFS       OLDPWD    OPTARG    OPTIND
OPTS      PATH      PS3       PS4
PWD       a         b         c
d         e         f         g
h         i         j         k
l         m         n         o
p         q         r         s
t         u         v         w
x         y         z         _
bel       bs        cr        esc
ht        ff        lf        vt
lb        dq        ds        rb
sq        var1      var2      

และนี่คือฟังก์ชั่น คำสั่งทั้งหมดนำหน้าด้วย w / \เพื่อหลีกเลี่ยงaliasการขยาย:

ns(){  ${1+":"} return
       case  $- in
       (c|"") ! set "OPTS=" "$@"
;;     (*c*)  ! set "OPTS=${-%c*}${-#*c}" "$@"
;;     (*)      set "OPTS=$-" "$@"
;;     esac
       OPTS=${1#*=} _PATH=$PATH PATH= LOCALS=     lf='
'      rb=\} sq=\' l= a= i=0 v= __=$_ IFS="       ""
"      command eval  LOCALS=\"LOCALS \
                     ARG0 ARGC HOME IFS OLDPWD OPTARG OPTIND OPTS     \
                     PATH PS3 PS4 PWD a b c d e f g h i j k l m n     \
                     o p q r s t u v w x y z _ bel bs cr esc ht ff    \
                     lf vt lb dq ds rb sq'"
       for a  do     i=$((i+1))
              if     \[ ns != "$a" ]         &&
                     \command -v "$a"  >&9   &&
              !      \alias "${a%%=*}" >&9 2>&9
              then   \eval 7>&- '\'    \
                     'ARGC=$((-i+$#))  ARG0=$a      HOME=~'           \
                     'OLDPWD=$OLDPWD   PATH=$_PATH  IFS=$IFS'         \
                     'OPTARG=$OPTARG   PWD=$PWD     OPTIND=1'         \
                     'PS3=$PS3 _=$__   PS4=$PS4     LOCALS=$LOCALS'   \
                     'a= b= c= d= e= f= g= i=0 j= k= l= m= n= o='     \
                     'p= q= r= s= t= u= v= w= x=0 y= z= ht=\   '      \
                     'cr=^M bs=^H ff=^L vt=^K esc=^[ bel=^G lf=$lf'   \
                     'dq=\" sq=$sq ds=$ lb=\{ rb=\}' \''"$v'          \
                            '\command eval       9>&2 2>&- '\'        \
                                   '\shift $((i-1));'                 \
                                   'case \${OPTS##*[!A-Za-z]*} in'    \
                                   '(*[!c$OPTS]*) >&- 2>&9"'\'        \
                                   '\set -"${OPTS%c*}${OPTS#*c}"'     \
                                   ';;esac; "$@" 2>&9 9>&-; PS4= '    \
                                   '\set  +"${-%c*}${-#*c}"'\'\"      \
                                          -'$OPTS \"\$?\"$sq";'       \
              '             \cd -- "${OLDPWD:-$PWD}"
                            \cd -P  ${ANDROID_SYSTEM+"/proc/self/fd/7"} /dev/fd/7/
                            \return "$(($??$?:$1))"
              else   case   ${a%%=*}      in
                     ([0-9]*|""|*[!_[:alnum:]]*)
                            \printf "%s: \${$i}: Invalid name: %s\n" \
                            >&2    "$0: ns()"   "'\''${a%%=*}'\''"
                            \return 2
              ;;     ("$a") v="$v $a=\$$a"
              ;;     (*)    v="$v ${a%%=*}=\${$i#*=}"
              ;;     esac
                     case " $LOCALS " in (*" ${a%%=*} "*)
              ;;     (*)    LOCALS=$LOCALS" ${a%%=*}"
              ;;     esac
              fi
       done'  7<.    9<>/dev/null
}

ฉลาดมาก! รูปแบบที่คล้ายกันถูกนำมาใช้เพื่อให้บรรลุสิ่งเดียวกันมากที่นี่: github.com/stephane-chazelas/misc-scripts/blob/master/locvar.sh
Zac B
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.