expr ดูเหมือนจะไม่ชอบวงเล็บ (ใช้ในคณิตศาสตร์เพื่อจัดลำดับความสำคัญผู้ประกอบการที่ชัดเจน):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
วิธีแสดงโอเปอเรเตอร์ที่สำคัญในการทุบตี?
expr ดูเหมือนจะไม่ชอบวงเล็บ (ใช้ในคณิตศาสตร์เพื่อจัดลำดับความสำคัญผู้ประกอบการที่ชัดเจน):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
วิธีแสดงโอเปอเรเตอร์ที่สำคัญในการทุบตี?
คำตอบ:
อีกวิธีในการใช้letbash builtin:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
บันทึก
ดังที่@ Stéphane Chazelas ชี้ให้เห็นว่าbashคุณควรใช้((...))เลขคณิตมากกว่าexprหรือletเพื่อความชัดเจน
สำหรับการพกพาใช้$((...))เช่นคำตอบ @Bernhard
letมีเหตุผลที่จะใช้ไม่ได้ มันไม่ได้เป็นแบบมาตรฐานหรือพกพาได้มากกว่า(( a = 3 * (2 + 1) ))(ทั้งคู่มาจากkshและมีให้เฉพาะใน ksh, bash และ zsh) และอ่านง่ายหรืออ้างง่าย ใช้a=$((3 * (2 + 1)))เป็นแบบพกพา
((a = 3 * (2 + 1) ))และอีกอันสำหรับความสะดวกในการพกพาa=$((3 * (2 + 1)))) ดังนั้นจึงไม่เป็นข้อสังเกตสำหรับคุณหรือคำตอบของคุณ และผู้ทำประตูสูงสุด
a=1 $[a+2] a=1 b=2 $[a+b]เหตุผลของพวกเขาคือหลีกเลี่ยงไวยากรณ์นั้นหรือไม่
คุณสามารถใช้การขยายเลขคณิตแทนได้
echo "$(( 3 * ( 2 + 1 ) ))"
9
exprในความเห็นส่วนตัวของฉันนี้มีลักษณะบิตดีกว่ากว่าการใช้
จาก man bash
การขยายตัว ทางเลขคณิตช่วยให้การประเมินผลของการแสดงออกทางคณิตศาสตร์และการทดแทนของผล รูปแบบสำหรับการขยายเลขคณิตคือ:
$((expression))การแสดงออกจะได้รับการปฏิบัติราวกับว่ามันอยู่ในเครื่องหมายคำพูดคู่ แต่เครื่องหมายคำพูดคู่ภายในวงเล็บไม่ได้รับการปฏิบัติเป็นพิเศษ โทเค็นทั้งหมดในนิพจน์ได้รับการขยายพารามิเตอร์การขยายสตริงการทดแทนคำสั่งและการลบเครื่องหมายคำพูด การขยายเลขคณิตอาจซ้อนกัน
การประเมินผลจะดำเนินการตามกฎที่ระบุไว้ด้านล่างภายใต้การประเมิน ARITHMETIC หากการแสดงออกไม่ถูกต้องทุบตีพิมพ์ข้อความที่ระบุความล้มเหลวและไม่มีการทดแทนเกิดขึ้น
ไม่มีเหตุผลที่จะใช้exprสำหรับเลขคณิตใน shell สมัยใหม่
POSIX กำหนด$((...))ผู้ประกอบการขยายตัว ดังนั้นคุณสามารถใช้สิ่งนั้นได้ในเชลล์ที่สอดคล้องกับ POSIX ทั้งหมด ( shของไลต์ยูนิกซ์สมัยใหม่ทั้งหมด, ขีดกลาง, ทุบตี, yash, mksh, zsh, posh, ksh ... )
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
kshยังแนะนำletbuiltin ซึ่งผ่านการแสดงออกทางคณิตศาสตร์ชนิดเดียวกันไม่ขยายไปสู่บางสิ่ง แต่ส่งคืนสถานะออกตามว่านิพจน์แก้ไขเป็น 0 หรือไม่เช่นในexpr:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
อย่างไรก็ตามในขณะที่การอ้างทำให้มันอึดอัดใจและไม่ชัดเจนมาก (ไม่เท่าที่exprแน่นอน) kshยังแนะนำ((...))รูปแบบทางเลือก:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
echo "$a is non-zero and 3 > 1"
fi
((a+=2))
ซึ่งมีความชัดเจนมากขึ้นและควรใช้แทน
letและ((...))มีเฉพาะในksh, และzsh ไวยากรณ์ควรเป็นที่ต้องการถ้าพกพาหอยอื่น ๆ เป็นสิ่งจำเป็นเป็นสิ่งจำเป็นสำหรับเปลือกหอยก่อน POSIX บอร์นเหมือน (ปกติบอร์นเปลือกหรือรุ่นแรกของ Almquist เชลล์)bash$((...))expr
ที่ด้านหน้าไม่ใช่บอร์นมีเชลล์จำนวนหนึ่งที่มีตัวดำเนินการทางคณิตศาสตร์ในตัว:
csh/ tcsh(อันที่จริงเชลล์ Unix ตัวแรกมีการประเมินผลทางคณิตศาสตร์ในตัว):
@ a = 3 * (2 + 1)akanga(ขึ้นอยู่กับrc)
a = $:'3 * (2 + 1)'ในฐานะที่เป็นบันทึกประวัติศาสตร์รุ่นเดิมของ Almquist shell ที่โพสต์บน usenet ในปี 1989 มีexprbuiltin (รวมกับจริงtest) แต่มันถูกลบออกในภายหลัง
: $((a = a*2))ล่ะ
$((...))เช่น zsh, ksh93 หรือ yash
exprเป็นคำสั่งภายนอกไม่ใช่ไวยากรณ์เชลล์พิเศษ ดังนั้นถ้าคุณต้องการexprเห็นอักขระพิเศษของเชลล์คุณจำเป็นต้องปกป้องพวกเขาจากการแยกเชลล์โดยการอ้างอิง นอกจากนี้exprต้องการให้แต่ละหมายเลขและโอเปอเรเตอร์ถูกส่งผ่านเป็นพารามิเตอร์แยกต่างหาก ดังนั้น:
expr 3 \* \( 2 + 1 \)
ถ้าคุณกำลังทำงานอยู่บนระบบยูนิกซ์โบราณจากปี 1970 หรือปี 1980 exprมีเหตุผลน้อยมากที่จะใช้ ในสมัยก่อนหอยไม่มีวิธีการคำนวณทางคณิตศาสตร์ในตัวและคุณต้องเรียกexprโปรแกรมอรรถประโยชน์แทน POSIX เชลล์ทั้งหมดมีคณิตศาสตร์ในตัวผ่านทางไวยากรณ์การขยายเลขคณิต
echo "$((3 * (2 + 1)))"
การสร้าง$((…))ขยายไปยังผลลัพธ์ของนิพจน์ทางคณิตศาสตร์ (เขียนเป็นทศนิยม) Bash เหมือนกับเชลล์ส่วนใหญ่รองรับเฉพาะเลขคณิตเลขจำนวนเต็ม modulo 2 64 (หรือ modulo 2 32สำหรับ bash เวอร์ชั่นเก่าและเชลล์อื่น ๆ บนเครื่อง 32 บิต)
Bash เสนอไวยากรณ์ความสะดวกสบายเพิ่มเติมเมื่อคุณต้องการทำงานที่ได้รับมอบหมายหรือเพื่อทดสอบว่าการแสดงออกเป็น 0 แต่ไม่สนใจเกี่ยวกับผลลัพธ์ โครงสร้างนี้ยังมีอยู่ใน ksh และ zsh แต่ไม่ได้อยู่ใน SH ธรรมดา
((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …
นอกจากเลขคณิตเลขจำนวนเต็มแล้วexprยังมีฟังก์ชันการจัดการสตริงอีกจำนวนหนึ่ง สิ่งเหล่านี้ก็ถูกรวมด้วยคุณสมบัติของเปลือกหอย POSIX ยกเว้นหนึ่งข้อ: expr STRING : REGEXPทดสอบว่าสตริงตรงกับ regexp ที่ระบุหรือไม่ POSIX เชลล์ไม่สามารถทำสิ่งนี้ได้หากไม่มีเครื่องมือภายนอก แต่ bash สามารถทำได้[[ STRING =~ REGEXP ]](ด้วยไวยากรณ์ regexp ที่แตกต่างกัน - exprเป็นเครื่องมือแบบคลาสสิกและใช้ BRE, bash ใช้ ERE)
ถ้าคุณไม่ดูแลสคริปต์ที่ทำงานบนระบบ 20 ปีคุณไม่จำเป็นต้องรู้ว่าexprมีตัวตนอยู่ ใช้เลขคณิตของเชลล์
expr foo : '\(.\)'ยังแยกข้อความ bash's BASH_REMATCHประสบความสำเร็จในสิ่งที่คล้ายกัน นอกจากนี้ยังไม่เปรียบเทียบสตริงซึ่ง POSIX [ไม่ได้ทำ (แม้คนหนึ่งจะคิดวิธีที่จะใช้sortสำหรับที่)
ใช้วงเล็บด้วยเครื่องหมายคำพูด:
expr 3 '*' '(' 2 '+' 1 ')'
9
คำพูดป้องกันไม่ให้ทุบตีตีความวงเล็บเป็นไวยากรณ์ทุบตี
exprบรรทัดคำสั่งจะต้องคั่นด้วยช่องว่าง ดังนั้น; ตัวอย่างเช่นจะไม่ทำงานexpr 3 "*" "(2" "+" "1)" (นอกจากนี้ BTW คุณอาจไม่จำเป็นต้องพูดถึง+)
whileและ[[มันเป็นไวยากรณ์ หากพวกเขาเป็นคำหลักพวกเขาจะไม่ถูกตีความเช่นนั้นในอาร์กิวเมนต์คำสั่ง คุณต้องมีเครื่องหมายอัญประกาศเพื่อที่ bash จะไม่แยกวิเคราะห์ แต่จะเห็นสตริงตามตัวอักษรแทน
หากคุณมี BC
echo '3 * (2 + 1)'|bc
9