expr
dường như không thích dấu ngoặc đơn (được sử dụng trong toán học để ưu tiên toán tử rõ ràng):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Làm thế nào để thể hiện ưu tiên của nhà điều hành trong bash?
expr
dường như không thích dấu ngoặc đơn (được sử dụng trong toán học để ưu tiên toán tử rõ ràng):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Làm thế nào để thể hiện ưu tiên của nhà điều hành trong bash?
Câu trả lời:
Một cách khác để sử dụng let
bash dựng sẵn:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Ghi chú
Như @ Stéphane Chazelas đã chỉ ra , trong bash
bạn nên sử dụng ((...))
để làm số học hơn expr
hoặc let
cho mức độ dễ đọc.
Đối với tính di động, sử dụng $((...))
như câu trả lời @Bernhard .
let
. Nó không phải là bất kỳ tiêu chuẩn hoặc di động hơn (( a = 3 * (2 + 1) ))
(cả hai đến từ ksh
và chỉ có sẵn trong ksh, bash và zsh) và nó ít dễ đọc hoặc dễ trích dẫn. Sử dụng a=$((3 * (2 + 1)))
để được xách tay.
((a = 3 * (2 + 1) ))
, một cho tính di động a=$((3 * (2 + 1)))
), vì vậy đó không phải là một lưu ý chống lại bạn hoặc câu trả lời của bạn mà là câu trả lời được chọn và cầu thủ ghi bàn hàng đầu.
a=1 $[a+2]
hoặc a=1 b=2 $[a+b]
. Là lý do của họ để tránh cú pháp đó?
Bạn có thể sử dụng mở rộng số học thay thế.
echo "$(( 3 * ( 2 + 1 ) ))"
9
Theo ý kiến cá nhân của tôi, điều này có vẻ tốt hơn một chút so với sử dụng expr
.
Từ man bash
Mở rộng số học Mở rộng số học cho phép đánh giá biểu thức số học và thay thế kết quả. Định dạng để mở rộng số học là:
$((expression))
Biểu thức được xử lý như thể nó nằm trong dấu ngoặc kép, nhưng trích dẫn kép bên trong dấu ngoặc đơn không được xử lý đặc biệt. Tất cả các mã thông báo trong biểu thức trải qua mở rộng tham số, mở rộng chuỗi, thay thế lệnh và xóa trích dẫn. Mở rộng số học có thể được lồng nhau.
Việc đánh giá được thực hiện theo các quy tắc được liệt kê dưới đây trong ĐÁNH GIÁ ARITHMETIC. Nếu biểu thức không hợp lệ, bash sẽ in một thông báo cho biết lỗi và không có sự thay thế nào xảy ra.
Không có lý do để sử dụng expr
cho số học trong các lớp vỏ hiện đại.
POSIX định nghĩa $((...))
toán tử mở rộng. Vì vậy, bạn có thể sử dụng nó trong tất cả các hệ vỏ tương thích POSIX ( sh
tất cả các ứng dụng Unix hiện đại, dash, bash, yash, mksh, zsh, posh, ksh ...).
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
ksh
cũng đã giới thiệu một let
nội dung được truyền cùng loại biểu thức số học, không mở rộng thành thứ gì đó nhưng trả về trạng thái thoát dựa trên việc biểu thức có giải quyết thành 0 hay không, như trong expr
:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
Tuy nhiên, vì trích dẫn làm cho nó khó xử và không dễ đọc (không đến mức tương tự như expr
tất nhiên), ksh
cũng giới thiệu một ((...))
hình thức thay thế:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
echo "$a is non-zero and 3 > 1"
fi
((a+=2))
cái nào dễ đọc hơn và nên được sử dụng thay thế.
let
và ((...))
chỉ có sẵn trong ksh
, zsh
và bash
. Các $((...))
cú pháp nên được ưa thích nếu tính di động với cái vỏ khác là cần thiết, expr
chỉ cần thiết cho vỏ trước POSIX Bourne-tương tự (thường là Bourne shell hoặc phiên bản đầu tiên của vỏ Almquist).
Ở mặt trước không phải là Bourne, có một vài shell với toán tử số học tích hợp:
csh
/ tcsh
(thực sự là vỏ Unix đầu tiên có tích hợp đánh giá số học):
@ a = 3 * (2 + 1)
akanga
(dựa trên rc
)
a = $:'3 * (2 + 1)'
như một ghi chú lịch sử, phiên bản gốc của vỏ Almquist, như được đăng trên usenet vào năm 1989 đã có một bản expr
dựng (thực sự được hợp nhất với test
), nhưng nó đã bị xóa sau đó.
: $((a = a*2))
?
$((...))
như zsh, ksh93 hoặc yash.
expr
là một lệnh bên ngoài, nó không phải là cú pháp shell đặc biệt. Do đó, nếu bạn muốn expr
xem các ký tự đặc biệt của shell, bạn cần bảo vệ chúng khỏi phân tích shell bằng cách trích dẫn chúng. Hơn nữa, expr
cần mỗi số và toán tử được truyền dưới dạng một tham số riêng. Do vậy:
expr 3 \* \( 2 + 1 \)
Trừ khi bạn đang làm việc trên một hệ thống unix cổ từ những năm 1970 hoặc 1980, có rất ít lý do để sử dụng expr
. Vào thời xưa, shell không có cách tích hợp để thực hiện số học và expr
thay vào đó bạn phải gọi tiện ích. Tất cả các vỏ POSIX đều có số học tích hợp thông qua cú pháp mở rộng số học .
echo "$((3 * (2 + 1)))"
Cấu trúc $((…))
mở rộng đến kết quả của biểu thức số học (được viết bằng số thập phân). Bash, giống như hầu hết các shell, chỉ hỗ trợ modulo số học 2 64 (hoặc modulo 2 32 cho các phiên bản cũ hơn của bash và một số shell khác trên các máy 32 bit).
Bash cung cấp một cú pháp tiện lợi bổ sung khi bạn muốn thực hiện các bài tập hoặc để kiểm tra xem một biểu thức có bằng 0 hay không nhưng không quan tâm đến kết quả. Cấu trúc này cũng tồn tại trong ksh và zsh nhưng không phải trong sh đơn giản.
((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …
Ngoài số học số nguyên, expr
cung cấp một vài hàm thao tác chuỗi. Những thứ này cũng được thay thế bởi các tính năng của shell POSIX, ngoại trừ một: expr STRING : REGEXP
kiểm tra xem chuỗi có khớp với biểu thức chính quy không. Một vỏ POSIX không thể làm điều này mà không có các công cụ bên ngoài, nhưng bash có thể với [[ STRING =~ REGEXP ]]
(với một cú pháp regrec khác - expr
là một công cụ cổ điển và sử dụng BRE, bash sử dụng ERE).
Trừ khi bạn đang duy trì các tập lệnh chạy trên các hệ thống 20 năm tuổi, bạn không cần biết rằng nó expr
đã từng tồn tại. Sử dụng số học shell.
expr foo : '\(.\)'
cũng không trích xuất văn bản. bash
's BASH_REMATCH
đạt được một cái gì đó tương tự. Nó cũng thực hiện so sánh chuỗi, điều mà POSIX [
không làm (mặc dù người ta có thể tưởng tượng ra các cách sử dụng sort
cho điều đó).
Sử dụng dấu ngoặc đơn với dấu ngoặc kép:
expr 3 '*' '(' 2 '+' 1 ')'
9
Các trích dẫn ngăn bash diễn giải dấu ngoặc đơn dưới dạng cú pháp bash.
expr
dòng lệnh phải được phân tách bằng khoảng trắng; vì thế; ví dụ, expr 3 "*" "(2" "+" "1)"
sẽ không hoạt động . (Ngoài ra, BTW, có lẽ bạn không cần trích dẫn +
.)
while
và [[
, chúng là cú pháp. Nếu chúng là từ khóa, chúng sẽ không được hiểu như vậy trong các đối số lệnh. Bạn cần trích dẫn để bash không phân tích cú pháp mà thay vào đó sẽ thấy một chuỗi ký tự.