/ bin / dash: kiểm tra xem $ 1 có phải là số không


12

Điều gì sẽ là cách tốt nhất để kiểm tra xem $ 1 có phải là số nguyên trong / bin / dash không?

Trong bash, tôi có thể làm:

[[ $1 =~ ^([0-9]+)$ ]]

Nhưng điều đó dường như không tuân thủ POSIX và dấu gạch ngang không hỗ trợ điều đó

Câu trả lời:


12

Sau đây phát hiện các số nguyên, tích cực hoặc tiêu cực, và hoạt động theo dashvà là POSIX:

lựa chọn 1

echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"

Lựa chọn 2

case "${1#[+-]}" in
    ''|*[!0-9]*)
        echo "Not an integer" ;;
    *)
        echo "Integer" ;;
esac

Hoặc, với một chút sử dụng lệnh :(nop):

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer

5
Điều gì nếu chuỗi chứa dòng mới? foo\n123\nbarkhông phải là một số nguyên, nhưng sẽ vượt qua bài kiểm tra này.
trời ơi

3
Phiên bản grep, đó là. Phiên bản trường hợp có vẻ chính xác.
trời ơi

5

Cho dù dash, bash, ksh, zsh, POSIX sh, hoặc posh( "một reimplementation của Bourne shell" sh ); các casecấu trúc là nhất phổ biến rộng rãi và đáng tin cậy:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac

Bạn đã thử nghiệm điều này dưới dash? Nó làm việc cho tôi dưới bashnhưng không dash.
John1024

Vâng, tôi đã thử nghiệm nó trên hệ thống của tôi với dash; để thẩm vấn kết quả tôi đã thêm echo $?sau lệnh case.
Janis

Tôi đã làm như vậy (Debian ổn định) nhưng không có niềm vui. Để biết ví dụ hoàn chỉnh phù hợp với tôi dưới dấu gạch ngang của tôi, hãy xem Tùy chọn 2 của tôi .
John1024

Hmm, tôi không có vỏ bourne gốc để kiểm tra. Các tài liệu mà tôi đã kiểm tra về "các tính năng [trong ksh] không phải trong vỏ bourne" ít nhất là không đề cập đến nó, vì vậy tôi cho rằng nó đã ở đó. Không? - Sau đó bỏ qua dấu ngoặc đơn hàng đầu. - OTOH, posh("một sự tái hiện của vỏ Bourne") cũng không có vấn đề gì với giải pháp đó.
Janis

1
@mikeerv; Có một số lý do tại sao tôi sử dụng luôn khớp dấu ngoặc đơn trong case; Một lý do là lỗi bạn mô tả, một lý do khác trong các trình soạn thảo có các tính năng dựa trên dấu ngoặc đơn phù hợp (vim), nó mang lại sự hỗ trợ tốt hơn nhiều, và không ít nhất tôi thấy nó phù hợp hơn với cá nhân. - WRT poshlà POSIX; tốt, trích dẫn từ trang người đàn ông mà tôi đã đề xuất một cái gì đó khác, nhưng tôi đoán không thể dựa vào những tuyên bố không chính thức như vậy. Vỏ bourne cũ dù sao cũng không còn quan trọng nữa khi chúng ta đang ở kỷ nguyên POSIX.
Janis

1

Bạn có thể sử dụng -eqthử nghiệm trên chuỗi, với chính nó:

$ dash -c 'a="a"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi' 
dash: 1: [: Illegal number: a
not a number
$ dash -c 'a="0xa"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: 0xa
not a number
$ dash -c 'a="-1"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
number

Nếu thông báo lỗi là một vấn đề, hãy chuyển hướng đầu ra lỗi sang /dev/null:

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no

1
Nó cũng sẽ nói rằng đó " 023 "là một con số. Lưu ý rằng nó hoạt động với dấu gạch ngang, nhưng không phải tất cả các vỏ POSIX khác vì hành vi không được chỉ định nếu các toán hạng là số nguyên thập phân ghi chú. Ví dụ với ksh, nó sẽ nói rằng SHLVLhoặc 1+1là một số.
Stéphane Chazelas

0

Hãy thử sử dụng nó như một mở rộng số học, và xem nếu nó hoạt động. Trên thực tế, bạn cần phải nghiêm ngặt hơn một chút, bởi vì việc mở rộng số học sẽ bỏ qua các không gian hàng đầu và dấu, chẳng hạn. Vì vậy, thực hiện mở rộng số học và đảm bảo rằng kết quả mở rộng khớp chính xác với biến ban đầu.

check_if_number()
{
    if [ "$1" = "$((${1}))" ] 2>/dev/null; then
        echo "Number!"
    else
        echo "not a number"
    fi
}

Điều này cũng sẽ chấp nhận số âm - nếu bạn thực sự muốn loại trừ chúng, hãy thêm một kiểm tra bổ sung cho $((${1} >= 0)).


1
dash không có[[
glenn jackman

@glennjackman Rất tiếc. Nó có $(( ... ))không? Nếu vậy, câu trả lời của tôi vẫn phải chính xác về mặt vật chất, tôi chỉ cần thêm một số trích dẫn thêm.
trời ơi

đó là câu trả lời của bạn: đi tìm hiểu.
glenn jackman

Có vẻ như nó làm, vì vậy phiên bản cập nhật của tôi nên thực hiện các mẹo. Mặc dù vậy, tôi không có dấu gạch ngang để kiểm tra nó - vì vậy hãy cho tôi biết nếu tôi bỏ lỡ điều gì khác.
trời ơi

Tôi đã thử: check_if_number 1.2và chức năng trả về: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024

0

Có lẽ với expr?

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi

cũng không matchphải \+là POSIX. Nó cũng sẽ nói 0 không phải là một số. Bạn muốnexpr "x$1" : 'x[0-9]\{1,\}$'
Stéphane Chazelas

0

Trong hệ thống POSIX, bạn có thể sử dụng expr :

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer

Nó sẽ nói rằng 0 không phải là số nguyên (và nói -12 là giải pháp bash của OP sẽ bị từ chối). Một số exprtriển khai sẽ nói rằng 9999999999999999999 không phải là số nguyên. POSIX không bảo đảm rằng nó sẽ hoạt động. Trong thực tế, trên một hệ thống GNU ít nhất, nó sẽ nói rằng "độ dài" là một số nguyên.
Stéphane Chazelas

Trong thử nghiệm của tôi, nó hoạt động ít nhất trong Debian và OSX. Nó nói số nguyên cho 0. Posix đảm bảo $ a phải là biểu thức hợp lệ (số nguyên) cho expr làm số học.
cuonglm

Ồ vâng, xin lỗi, tôi đã bỏ qua bài kiểm tra của bạn cho $? <2. Vẫn expr 9999999999999999999 + 0cho tôi trạng thái thoát 3 expr -12 + 0expr length + 0cho tôi trạng thái thoát 0 với GNU expr ( + stringcác lực stringđược coi là một chuỗi với GNU expr. expr "$a" - 0Sẽ hoạt động tốt hơn).
Stéphane Chazelas

@ StéphaneChazelas: Ồ, vâng, đã cập nhật câu trả lời của tôi. Tôi nghĩ -12là một số nguyên hợp lệ, và 9999999999999999999đã tràn.
cuonglm

0

Đây là một hàm đơn giản sử dụng cùng một phương thức như câu trả lời của muru :

IsInteger()      # usage: IsInteger string
{               #  returns: flag
        [ "$1" -eq "$1" ] 2> /dev/null
}

Thí dụ:

p= n=2a3; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
p= n=23;  IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"

Đầu ra:

'2a3' isn't an integer
'23' is an integer
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.