ความแตกต่างระหว่าง let, expr และ $ []


23

ฉันต้องการรู้ว่าอะไรคือความแตกต่างระหว่าง

a=$[1+1]
a=$((1+1))
let a=1+1
a=$(expr 1 + 1 )

4 ทั้งหมดกำหนดตัวแปร a ด้วย 2 แต่ความแตกต่างคืออะไร

จากสิ่งที่ฉันค้นพบจนถึงตอนนี้ก็คือ expr นั้นช้ากว่าเพราะมันไม่ใช่กระสุนจริงในตัว แต่ไม่มากกว่านั้น

คำตอบ:


25

ข้อตกลงเหล่านี้ทั้งหมดเกี่ยวกับคณิตศาสตร์ แต่มีหลายวิธีและตัวแปรถูกสร้างขึ้นด้วยวิธีการที่ต่างกัน สิ่งเหล่านี้บางอย่างเป็นของbashเชลล์โดยเฉพาะ

  • $((...))เรียกว่าการขยายตัวทางคณิตศาสตร์ซึ่งเป็นเรื่องปกติของbashและkshเปลือกหอย สิ่งนี้ยอมให้ทำเลขคณิตเลขจำนวนเต็มอย่างง่ายโดยไม่มีจุดลอยตัว ผลลัพธ์ของนิพจน์จะแทนที่นิพจน์ดังที่echo $((1+1))จะเป็นecho 2
  • ((...))เรียกว่าการประเมินผลทางคณิตศาสตร์และสามารถใช้เป็นส่วนหนึ่งของif ((...)); thenหรือwhile ((...)) ; doงบ การขยายตัวทางเลขคณิต$((..))แทนการส่งออกของการดำเนินการและสามารถใช้ในการกำหนดตัวแปรในi=$((i+1))แต่ไม่สามารถใช้ในงบเงื่อนไข
  • $[...] เป็นไวยากรณ์เก่าสำหรับการขยายเลขคณิตซึ่งเลิกใช้แล้ว ดูเพิ่มเติม สิ่งนี้อาจถูกเก็บไว้เพื่อไม่ให้bashสคริปต์เก่าแตก สิ่งนี้ใช้งานไม่ได้ksh93ดังนั้นฉันจึงคาดเดาว่าไวยากรณ์นี้เฉพาะสำหรับการทุบตี หมายเหตุ : ช่องว่างสำคัญมากที่นี่ อย่าสับสนกับสิ่งที่ชอบ$[1+1] [ $a -eq $b ]การ[เว้นวรรคเรียกว่าtestคำสั่งและโดยทั่วไปคุณจะเห็นมันในส่วนการตัดสินใจ มันแตกต่างกันมากในพฤติกรรมและวัตถุประสงค์
  • letเป็น a bashและkshคำสำคัญที่ช่วยให้การสร้างตัวแปรที่มีการประเมินทางคณิตศาสตร์อย่างง่าย หากคุณพยายามที่จะกำหนดสตริงที่นั่นเหมือนlet a="hello world"คุณจะได้รับข้อผิดพลาดทางไวยากรณ์ ทำงานในและbashksh93
  • $(...)คือการทดแทนคำสั่งโดยที่คุณรับเอาต์พุตของคำสั่งและกำหนดให้กับตัวแปรอย่างแท้จริง คำสั่งของคุณที่นี่คือexprซึ่งใช้อาร์กิวเมนต์ตำแหน่งเช่นexpr arg1 arg2 arg3ดังนั้นช่องว่างมีความสำคัญ มันเป็นเหมือนเครื่องคิดเลขบรรทัดคำสั่งขนาดเล็กสำหรับเลขจำนวนเต็มบวกกับบางสิ่งที่เป็นจริง / เท็จและ regex นี่คือคำสั่ง shell-neutral

นอกจากนี้ยังเป็นที่น่าสังเกตว่าส่วนขยายทางคณิตศาสตร์และการแทนที่คำสั่งถูกระบุโดยมาตรฐาน POSIXในขณะที่letและ$[...]ไม่ใช่


1
((...))จริงสามารถนำมาใช้สำหรับการมอบหมายงานในbash, kshและzsh: n=10; ((n+=10)); echo $nพิมพ์ 20 และ((x=1)); echo $xพิมพ์ 1.
Alexej Magura

1
@Alexej ขอบคุณ อัปเดตคำตอบแล้วส่วนนั้นก็ถูกเอาออก
Sergiy Kolodyazhnyy

11
  • letคำสั่งดำเนินการประเมินผลทางคณิตศาสตร์และเป็นเปลือกในตัว

    • เรียกใช้คำสั่งนี้และคุณจะไม่ได้รับอะไรเลย (ประเมินผลเท่านั้น):

      let 1+2
  • $(( ))ใช้เพื่อขยายเลขคณิต: อ่านที่นี่

    • เรียกใช้สิ่งนี้และคุณจะได้รับข้อผิดพลาด (เนื่องจากการขยาย):

      $((1+2))
  • $[ ] เป็นไวยากรณ์เก่าสำหรับการขยายเลขคณิต:

    รูปแบบเก่า $ [expression] เลิกใช้แล้วและจะถูกลบออกเมื่อมีการทุบตี Bash Man Page

  • expr เป็นคำสั่งไบนารีหากคุณต้องการขยายเลขคณิตภายในสถานการณ์ย่อยคำสั่งคุณสามารถใช้มันได้:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`

4

เนื่องจากคำตอบบางข้อข้างต้นกล่าวถึงเป็นพิเศษksh93มันก็คุ้มค่าที่จะสังเกตว่ามันสามารถทำเลขทศนิยมได้เช่น:

$ print $((1.0/3)) 
0.333333333333333333

คุณสามารถควบคุมความแม่นยำของเอาต์พุตด้วย printf เช่น:

$ printf "%.4f\n" $((1.0/3))
0.3333

ต้องระบุอย่างน้อยหนึ่งอาร์กิวเมนต์เป็นตัวเลขทศนิยมดังกล่าวข้างต้น หากทั้งคู่ระบุว่าเป็นจำนวนเต็มจะมีการคำนวณทางคณิตศาสตร์เฉพาะจำนวนเต็มเช่น:

$ print $((1/3))  
0

สิ่งนี้มีประโยชน์เมื่อคุณต้องการเลขทศนิยมในเชลล์สคริปต์เนื่องจากคุณสามารถหลีกเลี่ยงการเรียกคำสั่งภายนอก


เกิดขึ้นกับฉันว่าคุณอาจสนใจโพสต์คำตอบไปที่ฉันสามารถใช้เศษส่วน / ทศนิยมในสคริปต์ทุบตี? ทั้งๆที่มีชื่อผมคิดว่าบริบททำให้เห็นได้ชัดว่าเปลือกหอยบอร์นสไตล์อื่น ๆ ที่มีความเกี่ยวข้องซึ่งเป็นเหตุผลที่ผมโพสต์คำตอบ ตั้งแต่และมีความคล้ายคลึงกันมากขึ้น (โดยทั่วไป) มากกว่าอย่างใดอย่างหนึ่งดูเหมือนว่าสำหรับฉันแล้วคำตอบที่อิงกับคำถามนั้นอาจมีประโยชน์ทีเดียว zshkshbashzshkh93
Eliah Kagan

1

letไม่ทำงานใน cron ฉันคิดว่าเป็นเพราะletมีสภาพแวดล้อมเป็นของตัวเอง ใช้$((...))เนื่องจากเป็น POSIX ตัวอย่างเช่น,

let x=1+2
echo x=$x

ใน cron ให้ผลลัพธ์เป็น "x =" แต่ "x = 3" เมื่อเรียกใช้จากเชลล์

x=$((1+2))
echo x=$x

ผลลัพธ์เป็น "x = 3" ในทุกกรณี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.