Sự khác biệt giữa let, expr và $ []


23

Tôi muốn biết chính xác sự khác biệt giữa

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

Cả 4 đều gán biến a với 2, nhưng sự khác biệt là gì?

Từ những gì tôi phát hiện ra cho đến nay, đó là expr chậm hơn bởi vì nó không phải là một vỏ dựng thực tế. Nhưng không có gì hơn thế.

Câu trả lời:


25

Tất cả những điều này liên quan đến số học, nhưng theo những cách khác nhau và biến được tạo ra thông qua các phương tiện khác nhau. Một số trong số này là dành riêng cho bashđạn pháo, trong khi một số khác thì không.

  • $((...))được gọi là mở rộng số học , là điển hình của vỏ bashkshvỏ. Điều này cho phép thực hiện số học số nguyên đơn giản , mặc dù không có công cụ dấu phẩy động. Kết quả của biểu thức thay thế biểu thức, như trong echo $((1+1))sẽ trở thànhecho 2
  • ((...))được gọi là đánh giá số học và có thể được sử dụng như một phần của if ((...)); thenhoặc while ((...)) ; dobáo cáo. Mở rộng mở rộng số học $((..))thay thế đầu ra của hoạt động và có thể được sử dụng để gán các biến như trong i=$((i+1))nhưng không thể được sử dụng trong các câu lệnh có điều kiện.
  • $[...] là cú pháp cũ để mở rộng số học không được dùng nữa. Xem thêm . Điều này có khả năng được giữ để bashcác kịch bản cũ không bị phá vỡ. Điều này không hoạt động ksh93, vì vậy tôi đoán rằng cú pháp này là cụ thể bash. LƯU Ý : không gian rất quan trọng ở đây; đừng nhầm lẫn $[1+1]với những thứ như [ $a -eq $b ]. Các [khoảng trắng được gọi là testlệnh và bạn thường thấy nó trong các phần ra quyết định. Nó rất khác nhau trong hành vi và mục đích.
  • letlà một bashkshtừ khóa cho phép tạo biến với đánh giá số học đơn giản. Nếu bạn cố gắng gán một chuỗi ở đó như let a="hello world"bạn sẽ gặp lỗi cú pháp. Hoạt động trong bashksh93.
  • $(...)là sự thay thế lệnh, trong đó bạn thực sự lấy đầu ra của một lệnh và gán cho một biến. Lệnh của bạn ở đây là expr, trong đó có các đối số vị trí, như expr arg1 arg2 arg3, vì vậy khoảng trắng rất quan trọng. Nó giống như một máy tính dòng lệnh nhỏ cho số học số nguyên, cộng với một số loại công cụ đúng / sai và regex. Đây là một lệnh trung lập vỏ.

Cũng đáng lưu ý rằng việc mở rộng số học và thay thế lệnh được chỉ định theo tiêu chuẩn POSIX , trong khi let$[...]không.


1
((...))thực sự có thể được sử dụng cho các bài tập trong bash, kshzsh: n=10; ((n+=10)); echo $nin 20 và ((x=1)); echo $xin 1.
Alexej Magura

1
@Alexej Cảm ơn bạn. Trả lời cập nhật, phần đó đã bị xóa
Sergiy Kolodyazhnyy

11
  • letlệnh thực hiện đánh giá số học và là một vỏ được tích hợp sẵn.

    • Chạy lệnh này và bạn không nhận được gì (chỉ đánh giá):

      let 1+2
  • $(( ))được sử dụng để thực hiện mở rộng số học : đọc tại đây

    • Chạy cái này và bạn sẽ gặp lỗi (vì mở rộng):

      $((1+2))
  • $[ ] là cú pháp cũ để mở rộng số học:

    Định dạng cũ $ [biểu thức] không được dùng nữa và sẽ bị xóa trong bash sắp tới. Trang Bash Man

  • expr là một lệnh nhị phân, nếu bạn muốn thực hiện mở rộng số học trong một phân mục lệnh, bạn có thể sử dụng nó:

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

4

Vì một số câu trả lời ở trên đề cập cụ thể ksh93, đáng lưu ý rằng nó có thể làm toán học dấu phẩy động, ví dụ:

$ print $((1.0/3)) 
0.333333333333333333

Bạn có thể kiểm soát độ chính xác của đầu ra bằng printf, ví dụ:

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

Ít nhất một đối số phải được chỉ định là số dấu phẩy động như trên. Nếu cả hai được chỉ định là số nguyên thì chỉ có toán học số nguyên được thực hiện, ví dụ:

$ print $((1/3))  
0

Điều này có thể hữu ích khi bạn cần toán học dấu phẩy động trong tập lệnh shell vì bạn có thể tránh gọi lệnh bên ngoài.


Tôi nhận thấy rằng bạn có thể muốn gửi câu trả lời cho Tôi có thể sử dụng phân số / số thập phân trong tập lệnh bash không? Mặc dù tiêu đề, tôi nghĩ bối cảnh làm rõ rằng các vỏ kiểu Bourne khác có liên quan, đó là lý do tại sao tôi đăng một zshcâu trả lời . Vì kshbashgiống nhau hơn (nói chung) so với một trong hai zsh, đối với tôi, dường như kh93câu trả lời dựa trên câu hỏi đó có thể khá hữu ích.
Eliah Kagan

1

letkhông hoạt động trong cron. Tôi nghĩ đó là do letcó môi trường riêng của nó. Sử dụng $((...))vì đó là POSIX. Ví dụ,

let x=1+2
echo x=$x

trong cron, kết quả là "x =", nhưng "x = 3" khi chạy từ shell.

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

kết quả là "x = 3" trong mọi trường hợp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.