ปัญหาคือในกรณีที่เนื้อหาของ$x
ไม่ได้ถูกสุขอนามัยและมีข้อมูลที่อาจอยู่ภายใต้การควบคุมของผู้โจมตีในกรณีที่รหัสเชลล์อาจถูกใช้ในบริบทการยกระดับสิทธิ์ (เช่นสคริปต์ที่เรียกโดย setuid แอปพลิเคชันสคริปต์ sudoers หรือใช้เพื่อประมวลผลข้อมูลนอกเครือข่าย (CGI, DHCP hook ... ) โดยตรงหรือโดยอ้อม)
ถ้า:
x='(PATH=2)'
แล้ว:
x=$((1-$x)))
มีผลข้างเคียงของการตั้งค่าPATH
เป็น2
(เส้นทางสัมพัทธ์ที่อาจอยู่ภายใต้การควบคุมของผู้โจมตีได้เป็นอย่างดี) คุณสามารถแทนที่PATH
ด้วยLD_LIBRARY_PATH
หรือIFS
... สิ่งเดียวกันนี้เกิดขึ้นกับx=$((1-x))
ใน bash, zsh หรือ ksh (ไม่ใช่เส้นประหรือ yash ที่ยอมรับค่าคงที่ตัวเลขในตัวแปรที่มีเท่านั้น)
โปรดทราบว่า:
x=$((1-$x))
จะไม่ทำงานอย่างถูกต้องสำหรับค่าลบของ$x
ในเชลล์บางตัวที่ใช้ตัวดำเนินการ (เป็นทางเลือกตาม POSIX) --
(ลดลง) (เช่นเดียวกับx=-1
ที่หมายถึงการขอให้เชลล์ประเมิน1--1
ค่านิพจน์ทางคณิตศาสตร์) "$((1-x))"
ไม่ได้มีปัญหาตามที่ได้x
รับการขยายเป็นส่วนหนึ่งของการประเมินเลขคณิต (ไม่ใช่ก่อนหน้านี้)
ในbash
, zsh
และksh
(ไม่ใช่dash
หรือyash
) ถ้าx
เป็น:
x='a[0$(uname>&2)]'
จากนั้นการขยาย$((1-$x))
หรือ$((1-x))
ทำให้uname
คำสั่งนั้นถูกเรียกใช้งาน (สำหรับzsh
, a
จะต้องเป็นตัวแปรอาร์เรย์ แต่สามารถใช้psvar
เพื่ออินสแตนซ์สำหรับสิ่งนั้นได้)
สรุปหนึ่งไม่ควรใช้ uninitialised หรือไม่ปรุงแต่งข้อมูลภายนอกในการแสดงออกทางคณิตศาสตร์ในเปลือกหอย (หมายเหตุว่าการประเมินทางคณิตศาสตร์สามารถทำได้โดย$((...))
(หรือที่รู้จัก$[...]
ในbash
หรือzsh
) แต่ยังขึ้นอยู่กับเปลือกในที่let
, [
/ test
, declare/typeset/export...
, return
, break
, continue
, exit
, printf
, print
บิวด์อิน, ดัชนีอาเรย์((..))
และ[[...]]
โครงสร้างเพื่อตั้งชื่อไม่กี่)
ในการตรวจสอบว่าตัวแปรมีตัวเลขจำนวนเต็มฐานสิบที่แท้จริงคุณสามารถใช้ POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
ระวังว่า[0-9]
ในบางพื้นที่ตรงกับมากกว่า 0123456789 [[:digit:]]
ควรจะตกลง แต่ฉันจะไม่เดิมพัน
โปรดจำไว้ว่าตัวเลขที่มีเลขศูนย์นำหน้าจะถือว่าเป็นเลขฐานแปดในบางบริบท ( 010
บางครั้งคือ 10, บางครั้ง 8) และระวังว่าการตรวจสอบข้างต้นจะให้ตัวเลขที่อาจใหญ่กว่าจำนวนเต็มสูงสุดที่ระบบของคุณสนับสนุน ใช้จำนวนเต็มนั้นใน; bash เช่นถือว่า 18446744073709551616 เป็น 0 เท่ากับ 2 64 ) ดังนั้นคุณอาจต้องการเพิ่มการตรวจสอบพิเศษในคำสั่งกรณีข้างต้นเช่น:
(0?* | -0?*)
echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;
ตัวอย่าง:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
อ่านเพิ่มเติมได้ที่:
x='P=3'; : $(($x + 5))
จะตั้งP
8 แต่x='P=3'; : $((x + 5))
จะตั้งP
ไป3
(ในzsh
,ksh
หรือbash
) "สิ่งเดียวกันนี้เกิดขึ้นกับ$((x + 1))
... " ไม่ถูกต้องในขณะนี้ มันจะตั้งPATH
เพื่อ2
เป็นของเดิม