expr
ดูเหมือนจะไม่ชอบวงเล็บ (ใช้ในคณิตศาสตร์เพื่อจัดลำดับความสำคัญผู้ประกอบการที่ชัดเจน):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
วิธีแสดงโอเปอเรเตอร์ที่สำคัญในการทุบตี?
expr
ดูเหมือนจะไม่ชอบวงเล็บ (ใช้ในคณิตศาสตร์เพื่อจัดลำดับความสำคัญผู้ประกอบการที่ชัดเจน):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
วิธีแสดงโอเปอเรเตอร์ที่สำคัญในการทุบตี?
คำตอบ:
อีกวิธีในการใช้let
bash 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
ยังแนะนำlet
builtin ซึ่งผ่านการแสดงออกทางคณิตศาสตร์ชนิดเดียวกันไม่ขยายไปสู่บางสิ่ง แต่ส่งคืนสถานะออกตามว่านิพจน์แก้ไขเป็น 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 มีexpr
builtin (รวมกับจริง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