ไม่ใช่วิธีที่ง่ายที่สุดแต่คุณสามารถทำสิ่งต่อไปนี้:
$ IP=109.96.77.15
$ echo "$((${-+"(${IP//./"+256*("}))))"}&255))"
109
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>8&255))"
96
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>16&255))"
77
$ echo "$((${-+"(${IP//./"+256*("}))))"}>>24&255))"
15
ว่าควรจะทำงานใน ksh93 (ที่ว่า${var//pattern/replacement}
ผู้ประกอบการมาจาก) bash
4.3+, busybox sh
, yash
, mksh
และzsh
แม้ว่าแน่นอนในzsh
วิธีการที่มีที่ง่ายมาก ในเวอร์ชันที่เก่ากว่าbash
คุณจะต้องลบคำพูดภายใน มันใช้งานได้กับอัญประกาศภายในเหล่านั้นในเชลล์อื่น ๆ ส่วนใหญ่เช่นกัน แต่ไม่ใช่ ksh93
สมมติว่า$IP
มีการแทนค่า quad-decimal ที่ถูกต้องของที่อยู่ IPv4 (แม้ว่ามันจะใช้ได้สำหรับการแทน quad-hexadecimal เช่น0x6d.0x60.0x4d.0xf
(และแม้แต่เลขฐานแปดในบางเชลล์) แต่จะเอาท์พุทค่าเป็นทศนิยม) หากเนื้อหาของ$IP
มาจากแหล่งที่ไม่น่าเชื่อถือนั่นจะทำให้เกิดช่องโหว่ในการฉีดคำสั่ง
โดยทั่วไปในขณะที่เรากำลังแทนที่ทุก.
ใน$IP
กับ+256*(
เราจบลงด้วยการประเมินผล:
$(( (109+256*(96+256*(77+256*(15))))>> x &255 ))
ดังนั้นเราจึงกำลังสร้างจำนวนเต็ม 32 บิตออกจากผู้ที่ 4 ไบต์เช่นที่อยู่ IPv4 ในท้ายที่สุดคือ (แม้ว่าจะมีไบต์กลับ) ¹แล้วใช้>>
, &
ผู้ประกอบการที่จะดึงบิตไบต์ที่เกี่ยวข้อง
เราใช้ตัว${param+value}
ดำเนินการมาตรฐาน (ที่นี่$-
ซึ่งรับประกันว่าจะถูกตั้งค่าเสมอ) แทนที่จะเป็นเพียงvalue
เพราะมิฉะนั้นตัวแยกวิเคราะห์ทางคณิตศาสตร์จะบ่นเกี่ยวกับวงเล็บที่ไม่ตรงกัน เปลือกที่นี่สามารถหาปิด))
สำหรับการเปิด$((
และจากนั้นดำเนินการขยายที่อยู่ภายในที่จะมีผลในการแสดงออกทางคณิตศาสตร์ในการประเมิน
ด้วย$(((${IP//./"+256*("}))))&255))
แทนเปลือกจะรักษาที่สองและสาม)
ของที่นั่นในฐานะปิด))
สำหรับการ$((
และรายงานข้อผิดพลาดทางไวยากรณ์
ใน ksh93 คุณสามารถทำได้:
$ echo "${IP/@(*).@(*).@(*).@(*)/\2}"
96
bash
, mksh
, zsh
ได้คัดลอก ksh93 ของ${var/pattern/replacement}
ผู้ประกอบการ แต่ไม่ว่าเป็นส่วนหนึ่งในการจัดการการจับภาพกลุ่ม zsh
สนับสนุนด้วยไวยากรณ์ที่แตกต่าง:
$ setopt extendedglob # for (#b)
$ echo ${IP/(#b)(*).(*).(*).(*)/$match[2]}'
96
bash
ไม่สนับสนุนรูปแบบบางส่วนของกลุ่มการจับภาพในการจัดการผู้ประกอบการ regexp ตรงกัน${var/pattern/replacement}
แต่ไม่ได้อยู่ใน
POSIXly คุณจะใช้:
(IFS=.; set -o noglob; set -- $IP; printf '%s\n' "$2")
noglob
เพื่อหลีกเลี่ยงความผิดที่ไม่ดีสำหรับค่า$IP
เช่น10.*.*.*
, subshell ที่จะ จำกัด $IFS
ขอบเขตของการเปลี่ยนแปลงเหล่านั้นกับตัวเลือกและ
IPv ที่อยู่ IPv4 เป็นจำนวนเต็ม 32 บิตและตัวอย่าง 127.0.0.1 เป็นเพียงหนึ่งในหลาย ๆ ข้อความ ที่อยู่ IPv4 ทั่วไปเดียวกันนั้นของอินเทอร์เฟซแบบวนกลับสามารถแสดงเป็น 0x7f000001 หรือ 127.1 (อาจเป็นที่ที่เหมาะสมกว่าที่นี่เพื่อบอกว่ามันเป็นที่1
อยู่ในเครือข่ายคลาส A 127.0 / 8) หรือ 0177.0.1 หรือชุดอื่น ๆ ของ 1 ตัวเลข 4 ถึงแสดงเป็นฐานแปดทศนิยมหรือเลขฐานสิบหก คุณสามารถส่งต่อสิ่งเหล่านั้นทั้งหมดไปยังping
และคุณจะเห็นว่าพวกเขาทั้งหมดจะ ping localhost
หากคุณไม่คำนึงถึงผลข้างเคียงของการตั้งค่าตัวแปรชั่วคราวแบบสุ่ม (ที่นี่$n
) ในbash
หรือksh93
หรือzsh -o octalzeroes
หรือlksh -o posix
คุณสามารถแปลงการแทนค่าทั้งหมดเหล่านั้นกลับไปเป็นจำนวนเต็ม 32 บิตด้วย:
$((n=32,(${IP//./"<<(n-=8))+("})))
จากนั้นแยกส่วนประกอบทั้งหมดด้วย>>
/ &
ชุดเหมือนด้านบน
$ IP=0x7f000001
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ IP=127.1
$ echo "$((n=32,(${IP//./"<<(n-=8))+("})))"
2130706433
$ echo "$((n=32,((${IP//./"<<(n-=8))+("}))>>24&255))"
127
$ perl -MSocket -le 'print unpack("L>", inet_aton("127.0.0.1"))'
2130706433
mksh
ใช้จำนวนเต็ม 32 บิตที่มีลายเซ็นสำหรับนิพจน์ทางคณิตศาสตร์คุณสามารถใช้ที่$((# n=32,...))
นั่นเพื่อบังคับให้ใช้ตัวเลข 32 บิตที่ไม่ได้ลงชื่อ (และposix
ตัวเลือกสำหรับให้รับรู้ค่าคงที่แปด)
IFS
ที่read
นั่น:IFS=. read -a ArrIP<<<"$IP"