/ bin / dash: перевірте, чи є 1 $ числом


12

Який найкращий спосіб перевірити, чи є $ 1 цілим числом у / bin / dash?

У баші я міг би зробити:

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

Але це, здається, не сумісне з POSIX, і дефіс цього не підтримує

Відповіді:


12

Наступні виявляють цілі числа, додатні чи негативні, і працюють під dashі є POSIX:

Варіант 1

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

Варіант 2

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

Або з невеликим використанням команди :(nop):

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

5
Що робити, якщо рядок містить нові рядки? foo\n123\nbarне ціле число, але пройшло б цей тест.
godlygeek

3
Версія grep, тобто. Версія корпусу виглядає правильно.
godlygeek

5

Незалежно від того dash, bash, ksh, zsh, POSIX sh, або posh( "перевизначення Борна оболонки" sh ); caseконструкція є найбільш доступною і надійною:

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

Ви тестували це під dash? Це працює для мене під, bashале ні dash.
John1024

Так, я тестував це на своїй системі також і з dash; щоб допитати результат, який я додав echo $?після команди case.
Janis

Я робив те ж саме (стабільний Debian), але ніякої радості. Повний приклад, який працює для мене під моїм тире, див. Мій варіант 2 .
John1024

Хм, у мене немає доступної оригінальної оболонки для обмацування. Документи, які я оглядав про "особливості [в ksh] не в bourne shell", принаймні, не згадують про це, тому я припускаю, що він там був. Немає? - Тоді опустіть провідні дужки. - OTOH posh("повторне втілення оболонки Борна") також не має проблем з цим рішенням.
Яніс

1
@mikeserv; Є кілька причин, чому я використовую дужки, які завжди відповідають case; одна з причин - помилка, яку ви описуєте, інша - в редакторах, які мають функції, які покладаються на відповідні дужки (vim), вона дає набагато кращу підтримку, і не в останню чергу я вважаю, що це особисто розбірливіше, щоб вони відповідали. - WRT poshє POSIX; ну, цитата зі сторінки man, яку я дав, запропонувала щось інше, але я не можу покладатися на такі неофіційні заяви, я думаю. Стара оболонка Бурна все одно вже не така вже й значна, коли ми в епоху POSIX.
Яніс

1

Ви можете використовувати -eqтест на рядок із самим собою:

$ 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

Якщо повідомлення про помилку є проблемою, виведіть помилку переадресації на /dev/null:

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

1
Це також би сказало, що " 023 "це число. Зауважте, що він працює з тире, але не з усіма іншими оболонками POSIX, оскільки поведінка не визначена, якщо операнди є десятковими цілими числами. Наприклад кенійських шилінгів, було б сказати , що SHLVLі 1+1це число.
Стефан Шазелас

0

Спробуйте використовувати його як арифметичне розширення і подивіться, чи працює він. Насправді, ви повинні бути трохи суворішими, тому що арифметичні розширення ігнорують, наприклад, провідні та відсталі пробіли. Тому зробіть арифметичне розширення і переконайтеся, що розгорнутий результат точно відповідає оригінальній змінній.

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

Це також приймає негативні цифри - якщо ви дійсно хочете їх виключити, додайте додатковий чек для $((${1} >= 0)).


1
тире не має[[
glenn jackman

@glennjackman Whoops. Чи є $(( ... ))? Якщо так, то моя відповідь все ж має бути матеріально правильною, мені просто потрібно додати кілька додаткових цитувань.
godlygeek

це ваша відповідь: іди дізнайся.
glenn jackman

Схоже, це і є, тому моя оновлена ​​версія повинна зробити свою справу. Я не маю тире, щоб перевірити це, - тому дайте мені знати, якщо я пропустив щось інше.
godlygeek

Я спробував: check_if_number 1.2і функція повернулася: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024

0

Можливо, з expr?

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

ні POSIX matchне \+є. Також було б сказано, що 0 - це не число. Хочешexpr "x$1" : 'x[0-9]\{1,\}$'
Стефан Шазелас

0

У системі POSIX ви можете використовувати expr :

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

Він скаже, що 0 не є цілим числом (і скажімо, -12 - це те, що баш-рішення ОП відхилило б). Деякі exprреалізації скажуть, що 999999999999999999999 не є цілим числом. POSIX не дає гарантії, що це буде працювати. На практиці принаймні в системі GNU буде сказано, що "length" - ціле число.
Стефан Шазелас

У моєму тесті, він працює принаймні в Debian і OSX. Це говорить ціле число для 0. Posix гарантує, що $ a має бути дійсним виразом (цілим числом) для арифметики expr do.
cuonglm

О так, вибачте, я не помітив ваш тест на $? <2. Все-таки expr 9999999999999999999 + 0надає мені 3 статусу виходу expr -12 + 0та expr length + 0дає мені статус 0 виходу з GNU expr ( + stringзмушує stringрозглядатися як рядок з GNU expr. Працював expr "$a" - 0би краще).
Стефан Шазелас

@ StéphaneChazelas: О, так, оновив мою відповідь. Я думаю -12, що це дійсне ціле число і 9999999999999999999дало переповнення.
cuonglm

0

Ось проста функція, що використовує той самий метод, що і відповідь Муру :

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

Приклад:

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"

Вихід:

'2a3' isn't an integer
'23' is an integer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.