แค่ทำ:
case $1 in
(*:*) host=${1%:*} port=${1##*:};;
(*) host=$1 port=$default_port;;
esac
คุณอาจต้องการที่จะเปลี่ยนcase $1
ไปcase ${1##*[]]}
ยังบัญชีสำหรับค่า$1
เช่น[::1]
(ที่อยู่ IPv6 โดยไม่ต้องพอร์ตบางส่วน)
หากต้องการแยกคุณสามารถใช้ตัวดำเนินการแบ่ง + glob (ปล่อยให้ไม่มีการขยายพารามิเตอร์ไว้) เนื่องจากนั่นคือสิ่งที่เป็นประโยชน์
set -o noglob # disable glob part
IFS=: # split on colon
set -- $1 # split+glob
host=$1 port=${2:-$default_port}
(แม้ว่าจะไม่อนุญาตชื่อโฮสต์ที่มีเครื่องหมายโคลอน (เช่นสำหรับที่อยู่ IPv6 ข้างต้น))
ตัวดำเนินการแยก + glob นั้นขวางทางและก่อให้เกิดอันตรายมากในช่วงเวลาที่เหลือซึ่งมันดูเหมือนว่าจะใช้ได้เฉพาะเมื่อใดก็ตามที่ต้องการ (แม้ว่าฉันจะเห็นด้วยว่ามันยุ่งยากมากที่จะใช้โดยเฉพาะอย่างยิ่งเมื่อพิจารณาว่า POSIX sh
ไม่มี สนับสนุนขอบเขตท้องถิ่นค่าสำหรับตัวแปร ( $IFS
ที่นี่) หรือสำหรับตัวเลือก ( noglob
ที่นี่) (แม้ว่าash
และอนุพันธ์ชอบdash
คือบางส่วนของคนที่ทำ (ร่วมกับ AT & T ใช้งานของksh
, zsh
และbash
4.4 และสูงกว่า))
โปรดทราบว่าIFS=: read A B <<< "$1"
มีปัญหาของตัวเองไม่กี่:
- คุณลืม
-r
เครื่องหมายแบ็กสแลชซึ่งหมายถึงกระบวนการพิเศษบางอย่าง
- มันจะแยก
[::1]:443
ออกเป็น[
และ:1]:443
แทน[
และสตริงที่ว่างเปล่า (ซึ่งคุณจะต้องIFS=: read -r A B rest_ignored
หรือ[::1]
และ443
(ซึ่งคุณไม่สามารถใช้วิธีการที่)
- มันตัดทุกอย่างที่เกิดขึ้นครั้งแรกของอักขระขึ้นบรรทัดใหม่ดังนั้นจึงไม่สามารถใช้กับสตริงที่กำหนดเองได้ (เว้นแต่คุณจะใช้
-d ''
ในzsh
หรือbash
และข้อมูลไม่มีอักขระ NUL แต่จากนั้นให้สังเกตว่า herestrings (หรือ heredocs) เพิ่ม อักขระขึ้นบรรทัดใหม่พิเศษ!)
- ใน
zsh
(โดยที่ไวยากรณ์มาจาก) และbash
ที่นี่มีการใช้งานสตริงโดยใช้ไฟล์ชั่วคราวดังนั้นโดยทั่วไปจะมีประสิทธิภาพน้อยกว่าการใช้${x#y}
หรือแยกตัวดำเนินการ + glob