Убедитесь, что переменная является числом в оболочке UNIX

Как мне проверить, является ли переменная числом или содержит ли оно число в оболочке UNIX?

Заголовок спрашивает, является ли переменная числом, а описание спрашивает, содержит ли она число. Какой ты хочешь? Кроме того, когда вы говорите число d o, вы имеете в виду целое число или оно должно обрабатывать десятичные дроби?

gpojd 21.11.2008 22:35

Считаете ли вы 3,1415 числом?

Jens 15.05.2014 13:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
23
2
101 952
14

Ответы 14

Переменные оболочки не имеют типа, поэтому самый простой способ - использовать команду типа возврата test:

if [ $var -eq $var 2> /dev/null ]; then ...

(Или еще раз проанализируйте его с помощью регулярного выражения)

Если var пуст, это дает ложное срабатывание. Может быть: if [ -n "$var" -a $var -eq $var 2> /dev/null ]; then echo is num; else echo not a num; fi

Juan 02.05.2015 18:27

Также приятно, что это работает для базовых оболочек борна / корна (башизмы не нужны). Один недостаток: в тесте (1), который я использовал (FreeBSD 9, Fedora 20), это не удается, когда var чрезмерно инвертируется (например, --234), хотя арифметические операции работают (например, echo $((--234 * 2))).

Juan 02.05.2015 18:48
if echo $var | egrep -q '^[0-9]+$'; then
    # $var is a number
else
    # $var is not a number
fi

Я не знаю, правильно ли это, это проверяет, что это целое число (а не число). Я бы изменил регулярное выражение на '[0-9]', чтобы решить проблему, если вопрос находится в описании ("содержит"), и изменить его для обработки нецелых чисел, если это вопрос в заголовке ("равно ").

gpojd 21.11.2008 22:33

Сколько тысяч циклов тратят вилка, труба и egrep на такую ​​простую операцию, которую можно было бы выполнить в оболочке? Надеюсь, это не нужно в жестком цикле ...

Jens 15.05.2014 13:31

@Jens: Вы правы, этот ответ не так эффективен, как ответ, который не порождает подпроцесс, хотя в большинстве случаев это не имеет никакого практического значения. Я поддержал ваш лучший ответ.

Adam Rosenfield 15.05.2014 21:32

@AdamRosenfield Спасибо, это благородный жест перед лицом критики. Миру нужно больше такого отношения.

Jens 19.05.2014 12:27

Не забывайте отрицательные числа. Предполагая, что мы говорим только о целых числах (целых числах), а не о числах с плавающей запятой (реальных), т.е. числах, которые работают с числовыми операторами test (1) (-eq и т. д.), Мы могли бы настроить здесь метод регулярных выражений. включить отрицательные целые числа, например: echo $var | egrep -q '^-*[[:digit:]]+$' && echo is num || echo not num (конечно, только для основания 10). Это работает даже с чрезмерно отрицательными, но допустимыми числами, такими как ---- 234.

Juan 02.05.2015 18:39

В ksh93 или bash с включенной опцией extglob:

if [[ $var == +([0-9]) ]]; then ...

Чтобы обрабатывать отрицательные числа (даже чрезмерно, но законно отрицаемые, например --- 234), настройте это на if [[ $var == +(-*[[:digit:]]) ]]; then echo is num; else echo not num; fi. Приятно, что это обрабатывает пустой или неустановленный var, а также многословный var (например, «коричневая корова»). Используйте класс символов [:xdigit:] для чисел с основанием 16. Примечание: классы символов, не зависящие от локали (например, [: digit:]), похоже, не работают с ksh.

Juan 02.05.2015 19:30

Это быстро усложняется. Попробуйте проверить с помощью «коричневая корова», «123Q», «0xAbc», «123 Q», «-123», «----- 345». А разнообразные реализации «расширенных регулярных выражений» в bash / ksh усложняют задачу. Голосовать против из-за отсутствия переносимости для основных оболочек posix (скорее против метода, чем за ответ Даррона, так как он был очень откровенен с этим ограничением).

Juan 02.05.2015 20:33

вы можете помочь мне понять это: # x = 200 # [[+ ([0-9]) == $ x]] && номер эха || эхо не число> не число # [[$ x == + ([0-9])]] && эхо число || эхо не число> число

Thiago Conrado 03.07.2020 21:43

Это можно проверить с помощью регулярного выражения.

 ###    
    echo $var|egrep '^[0-9]+$'
    if [ $? -eq 0 ]; then
        echo "$var is a number"
    else
        echo "$var is not a number"
    fi

Почему это было добавлено? Именно этот метод был в ответе Адама в 2008 году (-1).

Juan 02.05.2015 19:39

Вот версия, использующая только функции, доступные в простой оболочке (т.е. она будет работать в sh), и с на один процесс меньше, чем при использовании grep:

if expr "$var" : '[0-9][0-9]*$'>/dev/null; then
    echo yes
else
    echo no
fi

Это проверяет, представляет ли $var целое число Только; настройте регулярное выражение по своему вкусу и обратите внимание, что аргумент регулярного выражения expr неявно привязан к началу.

Не поддерживает отрицательные целые числа (-123, --123).

Juan 02.05.2015 19:41

Для отрицательных чисел: expr "$var" : '-*[0-9][0-9]*$' && echo num || echo not num

Juan 02.05.2015 19:43

Проголосуйте за переносимость (например, отсутствие критики); небольшой недостаток для дополнительной вилки.

Juan 02.05.2015 19:45

Ни вилок, ни труб. Чистая оболочка POSIX:

case $var in
   (*[!0-9]*|'') echo not a number;;
   (*)           echo a number;;
esac

(Предполагается, что число: = строка цифр). Если вы хотите разрешить подписанные номера с одним ведущим - или +, удалите необязательный знак следующим образом:

case ${var#[-+]} in
   (*[!0-9]*|'') echo not a number;;
   (*)           echo a number;;
esac

Не обрабатывает отрицательные числа (например, -123, --123).

Juan 02.05.2015 20:00

@Juan: вот почему я прямо высказал это предположение.

Jens 02.05.2015 23:08

Справедливо. Я просто подумал, что проясню все различные решения. На некоторых других довольно легко поддерживать отрицательные числа. Попытка поддержать отрицательные числа с помощью этого метода (обычная подстановка) сложнее.

Juan 04.05.2015 01:40

@Juan Я добавил простую модификацию, разрешающую номера со знаком. Спасибо за вызов :-)

Jens 22.04.2017 12:31

Хорошее дополнение. По-прежнему не работает для извращенных, но действительно --123. Интересно, что / bin / sh <10 (sh -c 'var=--123; echo $(($var))') справляется с этим. Но freebsd> = 10 не работает.

Juan 28.04.2017 23:36

Оказалось, что --123 не работает в freebsd 10+ намеренно - чтобы явно указать, что оператор - не поддерживается. '- -123' и '- (- 123)' работают (но все еще проблематичны для вышеуказанного кода определения числа).

Juan 01.05.2017 04:21
a=123
if [ `echo $a | tr -d [:digit:] | wc -w` -eq 0 ]
then
    echo numeric
else
    echo ng
fi

numeric

a=12s3
if [ `echo $a | tr -d [:digit:] | wc -w` -eq 0 ]
then
    echo numeric
else
    echo ng
fi

ng

Не могли бы вы пояснить свое решение?

Steve Westbrook 02.10.2013 19:28

@StevenWestbrook: это удаляет цифры из $ a и считает, что осталось. Если что-то осталось, то это не строка из одних цифр («не числовая»).

Juan 02.05.2015 19:48

Не обрабатывает отрицательные числа (например, -123, --123). К сожалению, добавление поддержки отрицательных чисел с использованием этого тяжелого метода вилки означает добавление еще одного tr -d - в конвейер, я думаю.

Juan 02.05.2015 19:49

Вы можете изменить выражение tr (1) на '[[: digit:] -]', чтобы поймать отрицательные числа (или использовать [: xdigit:] для чисел с основанием 16), но это даст ложное срабатывание с чем-то вроде 123-54. (думает, что это действительное число).

Juan 02.05.2015 20:15

Я в некотором роде новичок в программировании оболочки, поэтому стараюсь найти самый простой и понятный Он просто проверит, что var больше или такое же, как 0 Я думаю, что это хороший способ выбора параметров ... может быть не то, что вообще ...:

if [ $var -ge 0 2>/dev/null ] ; then ...

если [$ var -ge 0 -o $ var -lt 0]; then ... # для обработки отрицательных чисел

John Eikenberry 27.11.2015 00:46
if echo $var | egrep -q '^[0-9]+$'

На самом деле это не работает, если var многострочный.

т.е.

var = "123
qwer"

Особенно, если var исходит из файла:

var=`cat var.txt`

Это самый простой:

if [ "$var" -eq "$var" ] 2> /dev/null
then echo yes
else echo no
fi

Небольшой отрицательный голос за повторение ответа Петра 2008 года без указания авторства. Та же проблема с ложным срабатыванием, что и у этой (добавьте -n "$var", чтобы поймать пустую / неустановленную переменную). Смотрите комментарии там. Хороший аргумент в отношении потенциальных ложных срабатываний для многострочной проблемы.

Juan 02.05.2015 20:20

Вы можете сделать это с помощью простой тестовой команды.

$ test ab -eq 1 >/dev/null 2>&1
$ echo $?
2

$ test 21 -eq 1 >/dev/null 2>&1
$ echo $?
1

$ test 1 -eq 1 >/dev/null 2>&1
$ echo $?
0

Таким образом, если статус выхода равен 0 или 1, тогда это целое число, но если статус exis равен 2, то это не число.

Downvote - по сути, то же самое, что и ответ @ Piotr 2008 года. Разве никто не просматривает существующие ответы перед тем, как ответить - особенно в той же теме (не говоря уже о других подобных темах)?

Juan 02.05.2015 20:22

Вот тест без регулярных выражений (код tcsh):

Создайте файл с контрольным номером:

#! /usr/bin/env tcsh
if ( "$*" == "0" ) then
    exit 0 # number
else
    ((echo "$*" | bc) > /tmp/tmp.txt) >& /dev/null
    set tmp = `cat /tmp/tmp.txt`
    rm -f /tmp/tmp/txt
    if ( "$tmp" == "" || $tmp == 0 ) then
        exit 1 # not a number
    else
        exit 0 # number
    endif

endif

и беги

chmod +x checknumber

Использовать

checknumber -3.45

и вы получите результат как errorlevel ($?).

Вы можете легко его оптимизировать.

Вилка тяжелая. Существуют более легкие реализации для целых чисел (см. Предыдущие ответы), если все, что у вас есть, - это csh. Незначительный голос за обработку с плавающей запятой, хотя я предполагаю, что это не то, что хотел OP (OP был довольно расплывчатым в описании проблемы).

Juan 02.05.2015 20:27

ЦЕЛОЕ

if echo "$var" | egrep -q '^\-?[0-9]+$'; then 
    echo "$var is an integer"
else 
    echo "$var is not an integer"
fi

тесты (с var = 2 и т. д.):

2 is an integer
-2 is an integer
2.5 is not an integer 
2b is not an integer

КОЛИЧЕСТВО

if echo "$var" | egrep -q '^\-?[0-9]*\.?[0-9]+$'; then 
    echo "$var is a number"
else 
    echo "$var is not a number"
fi

тесты (с var = 2 и т. д.):

2 is a number
-2 is a number
-2.6 is a number
-2.c6 is not a number
2. is not a number
2.0 is a number

Конечно, .6 - это число. Команда также показывает это как число. Также 4. - это число, но эта команда сообщает, что это не число.

Oguz 06.10.2015 10:22

Принимая значение из командной строки и показывая ВХОД ДЕСЯТИЧНЫЙ / НЕ-ДЕСЯТИЧНЫЙ и ЧИСЛО или нет:

NUMBER=$1

            IsDecimal=`echo "$NUMBER" | grep "\."`

if [ -n "$IsDecimal" ]
then
            echo "$NUMBER is Decimal"
            var1=`echo "$NUMBER" | cut -d"." -f1`
            var2=`echo "$NUMBER" | cut -d"." -f2`

            Digit1=`echo "$var1" | egrep '^-[0-9]+$'`
            Digit2=`echo "$var1" | egrep '^[0-9]+$'`
            Digit3=`echo "$var2" | egrep '^[0-9]+$'`


            if [ -n "$Digit1" ] && [ -n "$Digit3" ]
            then
                echo "$NUMBER is a number"
            elif [ -n "$Digit2" ] && [ -n "$Digit3" ]
            then
                echo "$NUMBER is a number"

            else
                echo "$NUMBER is not a number"
            fi
else
            echo "$NUMBER is not Decimal"

            Digit1=`echo "$NUMBER" | egrep '^-[0-9]+$'`
            Digit2=`echo "$NUMBER" | egrep '^[0-9]+$'`

            if [ -n "$Digit1" ] || [ -n "$Digit2" ]; then
                echo "$NUMBER is a number"
            else
                echo "$NUMBER is not a number"
            fi
fi
( test ! -z "$num" && test "$num" -eq "$num" 2> /dev/null ) && {
   # $num is a number
}

Это приведет к сбою непривлекательным образом из-за отсутствие цитирования для любого нетривиального строкового ввода.

tripleee 21.03.2021 19:34

@tripleee исправлено

cab404 25.03.2021 13:38

Но действительно ли необходима проверка -z? test "" -eq "" 2>/dev/null делает то, что я ожидаю здесь (старый Bash 3.2 на стандартной macOS). Тем не менее, круглые скобки кажутся излишними (и стоят вам ненужной подоболочки).

tripleee 25.03.2021 14:10

Другие вопросы по теме