เพื่อให้ได้ผลลัพธ์เดียวกันกับที่คุณบันทึกในคำถามของคุณสิ่งที่จำเป็นต้องมีคือ:
PS1='${PS2c##*[$((PS2c=0))-9]}- > '
PS2='$((PS2c=PS2c+1)) > '
คุณไม่จำเป็นต้องบิด ทั้งสองบรรทัดนี้จะทำทุกอย่างในเชลล์ที่อ้างว่าใกล้เคียงกับ POSIX
- > cat <<HD
1 > line 1
2 > line $((PS2c-1))
3 > HD
line 1
line 2
- > echo $PS2c
0
แต่ฉันชอบสิ่งนี้ และฉันต้องการแสดงให้เห็นพื้นฐานของสิ่งที่ทำให้งานนี้ดีขึ้นเล็กน้อย ดังนั้นฉันจึงแก้ไขสิ่งนี้เล็กน้อย ฉันติดมันใน/tmp
ตอนนี้ แต่ฉันคิดว่าฉันจะเก็บมันไว้เพื่อตัวเองเช่นกัน ที่นี่:
cat /tmp/prompt
พรอมต์สคริปต์:
ps1() { IFS=/
set -- ${PWD%"${last=${PWD##/*/}}"}
printf "${1+%c/}" "$@"
printf "$last > "
}
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
PS2='$((PS2c=PS2c+1)) > '
หมายเหตุ: เมื่อเร็ว ๆ นี้ได้เรียนรู้เกี่ยวกับyashฉันสร้างมันเมื่อวาน ไม่ว่าจะด้วยเหตุผลใดก็ตามมันจะไม่พิมพ์ไบต์แรกของอาร์กิวเมนต์ทุกตัวด้วย%c
สตริง - แม้ว่าเอกสารนั้นจะมีความเฉพาะเจาะจงเกี่ยวกับส่วนขยายแบบกว้างสำหรับรูปแบบนั้นและอาจเกี่ยวข้องกัน - แต่มันก็ใช้ได้ดี%.1s
นั่นคือสิ่งทั้งหมด มีสองสิ่งหลักเกิดขึ้นที่นั่น และนี่คือสิ่งที่ดูเหมือนว่า:
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 >
วจีวิภาค $PWD
ทุกครั้งที่$PS1
มีการประเมินผลจะแยกวิเคราะห์และพิมพ์$PWD
เพื่อเพิ่มไปยังพรอมต์ แต่ฉันไม่ชอบ$PWD
หน้าจอที่เบียดเสียดของฉันดังนั้นฉันต้องการแค่ตัวอักษรตัวแรกของ breadcrumb ทุกอันในเส้นทางปัจจุบันจนถึงไดเรกทอรีปัจจุบันซึ่งฉันต้องการเห็นเต็ม แบบนี้:
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cd /
/ > cd ~
/h/mikeserv >
มีไม่กี่ขั้นตอนที่นี่:
IFS=/
เรากำลังจะมีการแยกในปัจจุบัน$PWD
และวิธีที่เชื่อถือได้มากที่สุดที่จะทำคือมีแยก$IFS
/
ไม่จำเป็นต้องยุ่งกับมันเลย - การแยกทั้งหมดจากที่นี่ออกมาจะถูกกำหนดโดย$@
อาร์เรย์พารามิเตอร์ของเชลล์ในคำสั่งถัดไปเช่น:
set -- ${PWD%"${last=${PWD##/*/}}"}
ดังนั้นหนึ่งนี้หากินเล็ก ๆ น้อย ๆ แต่สิ่งที่สำคัญคือการที่เราแยกกำลัง$PWD
บน/
สัญลักษณ์ ฉันยังใช้การขยายพารามิเตอร์เพื่อกำหนดให้กับ$last
ทุกสิ่งหลังจากค่าใด ๆ ที่เกิดขึ้นระหว่าง/
เครื่องหมายสแลชซ้ายและขวาสุด ด้วยวิธีนี้ฉันรู้ว่าถ้าฉันแค่/
และมีเพียงคนเดียว/
ก็$last
จะยังคงเท่ากับทั้งหมด$PWD
และ$1
จะว่างเปล่า เรื่องนี้ ฉันยังตัด$last
จากปลายหางของก่อนที่จะกำหนดมัน$PWD
$@
printf "${1+%c/}" "$@"
ดังนั้นที่นี่ - ตราบใดที่${1+is set}
เราprintf
แรก%c
haracter ของการขัดแย้งแต่ละเปลือกของเรา - ซึ่งเราได้ตั้งเพียงเพื่อไดเรกทอรีในปัจจุบันของเราในแต่ละ$PWD
- น้อยไดเรกทอรีด้านบน - /
แยก ดังนั้นโดยพื้นฐานแล้วเราแค่พิมพ์ตัวอักษรแรกของทุก ๆ ตัวในไดเรกทอรี$PWD
แต่ตัวแรกสุด มันเป็นสิ่งสำคัญที่จะตระหนักถึงแม้ว่านี้จะเกิดขึ้นหาก$1
ได้รับการกำหนดที่ทุกคนซึ่งจะไม่เกิดขึ้นที่ราก/
หรืออย่างใดอย่างหนึ่งลบออกจากเช่นใน/
/etc
printf "$last > "
$last
เป็นตัวแปรที่ฉันเพิ่งกำหนดให้กับสารบบอันดับต้น ๆ ของเรา ดังนั้นตอนนี้นี่คือไดเรกทอรียอดนิยมของเรา มันพิมพ์ว่าคำสั่งสุดท้ายได้หรือไม่ และใช้เวลาเล็กน้อย>
ในการวัดที่ดี
แต่สิ่งที่เกี่ยวกับการบุกรุก?
แล้วก็มีเรื่องของ$PS2
เงื่อนไข ฉันแสดงให้เห็นก่อนหน้านี้ว่าวิธีนี้สามารถทำได้ซึ่งคุณยังสามารถหาได้ด้านล่าง - นี่คือปัญหาของขอบเขต แต่มีอะไรเพิ่มเติมอีกนิดหน่อยถ้าคุณไม่ต้องการที่จะเริ่มทำสprintf \b
ปอตและพยายามสร้างความสมดุลให้กับตัวละครของพวกเขา ดังนั้นฉันทำสิ่งนี้:
PS1='$(ps1)${PS2c##*[$((PS2c=0))-9]}'
อีกครั้ง${parameter##expansion}
บันทึกวัน มันแปลกเล็กน้อยที่นี่ - เราตั้งค่าตัวแปรในขณะที่เราถอดมันเอง เราใช้ค่าใหม่ - ตั้งแถบกลาง - เป็นกลมจากที่เราตัด เห็นไหม เราตัดทั้งหมดออกจากหัวของตัวแปรที่เพิ่มขึ้นของเรากับตัวละครที่ผ่านมาซึ่งได้อะไรจาก##*
[$((PS2c=0))-9]
เรารับประกันด้วยวิธีนี้ไม่ให้ส่งออกค่าและเรายังคงกำหนดมัน มันค่อนข้างเท่ห์ - ฉันไม่เคยทำมาก่อน แต่ POSIX ยังรับประกันเราว่านี่เป็นวิธีพกพาที่สุดที่สามารถทำได้
และต้องขอบคุณ POSIX ที่ระบุ${parameter} $((expansion))
ซึ่งเก็บคำจำกัดความเหล่านี้ไว้ในเชลล์ปัจจุบันโดยไม่ต้องการให้เราตั้งค่าไว้ในเชลล์ย่อยที่แยกจากกันโดยไม่คำนึงถึงตำแหน่งที่เราประเมินพวกมัน และนี่คือเหตุผลที่มันทำงานในdash
และsh
ก็เช่นกันเช่นเดียวกับในและbash
zsh
เราไม่ใช้การหลีกเลี่ยงเชลล์ / เทอร์มินัลและเราปล่อยให้ตัวแปรทดสอบตัวเอง นั่นคือสิ่งที่ทำให้โค้ดพกพารวดเร็ว
ส่วนที่เหลือค่อนข้างง่าย - เพียงแค่เพิ่มเคาน์เตอร์ของเราทุกครั้งที่$PS2
มีการประเมินจนกว่าจะ$PS1
รีเซ็ตอีกครั้ง แบบนี้:
PS2='$((PS2c=PS2c+1)) > '
ดังนั้นตอนนี้ฉันสามารถ:
DASH DEMO
ENV=/tmp/prompt dash -i
/h/mikeserv > cd /etc
/etc > cd /usr/share/man/man3
/u/s/m/man3 > cat <<HERE
1 > line 1
2 > line 2
3 > line $((PS2c-1))
4 > HERE
line 1
line 2
line 3
/u/s/m/man3 > printf '\t%s\n' "$PS1" "$PS2" "$PS2c"
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
0
/u/s/m/man3 > cd ~
/h/mikeserv >
SH DEMO
มันทำงานเหมือนกันในbash
หรือsh
:
ENV=/tmp/prompt sh -i
/h/mikeserv > cat <<HEREDOC
1 > $( echo $PS2c )
2 > $( echo $PS1 )
3 > $( echo $PS2 )
4 > HEREDOC
4
$(ps1)${PS2c##*[$((PS2c=0))-9]}
$((PS2c=PS2c+1)) >
/h/mikeserv > echo $PS2c ; cd /
0
/ > cd /usr/share
/u/share > cd ~
/h/mikeserv > exit
ดังที่ฉันได้กล่าวไปแล้วปัญหาหลักคือคุณต้องพิจารณาว่าคุณทำการคำนวณของคุณที่ไหน คุณไม่ได้สถานะในพาเรนต์เชลล์ดังนั้นคุณจึงไม่ต้องคำนวณ คุณได้รับสถานะใน subshell - นั่นคือที่ที่คุณคำนวณ แต่คุณทำนิยามในเชลล์พาเรนต์
ENV=/dev/fd/3 sh -i 3<<\PROMPT
ps1() { printf '$((PS2c=0)) > ' ; }
ps2() { printf '$((PS2c=PS2c+1)) > ' ; }
PS1=$(ps1)
PS2=$(ps2)
PROMPT
0 > cat <<MULTI_LINE
1 > $(echo this will be line 1)
2 > $(echo and this line 2)
3 > $(echo here is line 3)
4 > MULTI_LINE
this will be line 1
and this line 2
here is line 3
0 >
man 1 mktemp
ใช้ดูไฟล์ที่ซ่อน