Chuỗi đối số thành số nguyên trong bash


74

Cố gắng tìm ra cách chuyển đổi một đối số thành một số nguyên để thực hiện số học trên, sau đó in ra, nói addOne.sh:

echo $1 + 1
>>sh addOne.sh 1
prints 1 + 1

Tôi cố gắng định dạng câu hỏi của bạn, nhưng vẫn chưa rõ ràng. printf "1 + %s\n" $1 won't do ?
Archemar

Câu trả lời:


88

Trong bash, người ta không "chuyển đổi một đối số thành một số nguyên để thực hiện số học". Trong bash, các biến được coi là số nguyên hoặc chuỗi tùy thuộc vào ngữ cảnh.

Để thực hiện số học, bạn nên gọi toán tử mở rộng số học $((...)). Ví dụ:

$ a=2
$ echo "$a + 1"
2 + 1
$ echo "$(($a + 1))"
3

hoặc thường được ưa thích:

$ echo "$((a + 1))"
3

Bạn nên lưu ý rằng bash (trái ngược với ksh93, zsh hoặc yash) chỉ thực hiện số học số nguyên . Nếu bạn có số dấu phẩy động (số có số thập phân), thì có các công cụ khác để hỗ trợ. Ví dụ bc: sử dụng :

$ b=3.14
$ echo "$(($b + 1))"
bash: 3.14 + 1: syntax error: invalid arithmetic operator (error token is ".14 + 1")
$ echo "$b + 1" | bc -l
4.14

Hoặc bạn có thể sử dụng hệ vỏ với hỗ trợ số học dấu phẩy động thay vì bash:

zsh> echo $((3.14 + 1))
4.14

Sử dụng $ (()) hoặc (()) là không an toàn nếu bạn không biết chuỗi là gì (như đầu vào của người dùng). Xem xét điều này: foo = foo ((foo + = 0)) Điều này sẽ làm hỏng tập lệnh khi nó cố gắng đánh giá đệ quy foo. Tương tự với: foo = foo foo = $ ((foo + 0))
nghệ thuật

12

Cách khác, bạn có thể sử dụng expr

Ví dụ:

$ version="0002"
$ expr $version + 0
2
$ expr $version + 1
3

10

Trong bash, bạn có thể thực hiện chuyển đổi từ bất cứ thứ gì sang số nguyên bằng printf -v :

printf -v int '%d\n' "$1" 2>/dev/null

Số nổi sẽ được chuyển đổi thành số nguyên, trong khi mọi thứ không giống như số sẽ được chuyển đổi thành 0. Số mũ sẽ được cắt thành số trước e

Thí dụ:

$ printf -v int '%d\n' 123.123 2>/dev/null
$ printf '%d\n' "$int"
123
$ printf -v int '%d\n' abc 2>/dev/null
$ printf '%d\n' "$int"
0
$ printf -v int '%d\n' 1e10 2>/dev/null
$ printf '%d\n' "$int"
1

2
Trong các shell khác mà không có printf -vđiều này có thể đạt được với sự thay thế lệnh:int="$(printf '%d' 123.123 2>/dev/null)"
Adrian Günter

2
Điều này không hoạt động trong bash.
Michael Martinez

@MichaelMartinez bạn có chắc không? Bạn đã bashsử dụng phiên bản nào?
cuonglm

GNU bash, phiên bản 4.2.46 (1) -release (x86_64-redhat-linux-gnu)
Michael Martinez

5

Một tình huống tương tự đã xuất hiện gần đây khi phát triển các tập lệnh bash để chạy trong cả môi trường Linux và OSX. Kết quả của một lệnh trong OSX đã trả về một chuỗi chứa mã kết quả; ví dụ " 0". Tất nhiên, điều này không thể kiểm tra chính xác trong trường hợp sau:

if [[ $targetCnt != 0 ]]; then...

Giải pháp là buộc (tức là 'chuyển đổi') kết quả thành một số nguyên, tương tự như những gì @ John1024 đã trả lời ở trên để nó hoạt động như mong đợi:

targetCnt=$(($targetCnt + 0))
if [[ $targetCnt != 0 ]]; then...

3
==vv trong [[(cũng [aka test) làm so sánh chuỗi. Có các toán tử khác nhau để so sánh số học, ví dụ [[ $targetcnt -ne 0 ]]; xem manpage (hoặc thông tin) dưới Biểu thức có điều kiện. Để cắt các không gian cụ thể, bạn có thể sử dụng [với mở rộng biến không được trích dẫn [ $targetcnt == 0 ]để có được các từ mặc định (KHÔNG được thực hiện [[) nhưng nói chung cách tiếp cận đó dẫn bạn đến nguy hiểm.
dave_thndry_085

-2

quan tâm đến mã màu, ngay cả trong dấu vết ( -x) chúng sẽ không xuất hiện, điều sẽ cho đi là chuỗi được cho là một số được gói trong dấu ngoặc kép cho dù bạn in nó như thế nào.


1
Bỏ phiếu xuống, vì tôi thấy câu trả lời của bạn hơi không rõ ràng. Có lẽ bạn có thể thêm những gì các kịch bản nên được sửa chữa?
Time4Tea

đây là câu trả lời hàng đầu trong tìm kiếm bash + số nguyên + chuỗi vì vậy tôi đã thêm một phần thông tin liên quan đến nó mà không được bao gồm trong các câu trả lời, đó là khi các chuỗi được bọc bằng mã màu, có thể không rõ tại sao các thao tác như $((var+var))không thành công mặc dù nếu bạn echohoặc printfcả hai vars họ giống nhau. Tôi không biết cách khắc phục vì tôi chỉ có thể sửa nó bằng cách vô hiệu hóa mã màu ở nguồn đầu ra. Để phát hiện nó trong các dấu vết các bản ghi bạn sẽ thấy những biến vi phạm giao như var='0'trong khi nó chỉ đơn giản nênvar=0
untore

Những gì bạn có thể làm là đảm bảo đầu ra không có mã màu với sednếu bạn không thể vô hiệu hóa nó
untore
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.