expr
не похоже на круглые скобки (используется в математике для явного приоритета оператора):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Как выразить приоритет оператора в bash?
expr
не похоже на круглые скобки (используется в математике для явного приоритета оператора):
expr 3 * (2 + 1)
bash: syntax error near unexpected token `('
Как выразить приоритет оператора в bash?
Ответы:
Еще один способ использовать let
встроенную Bash:
$ let a="3 * (2 + 1)"
$ printf '%s\n' "$a"
9
Запись
Как отметил @ Stéphane Chazelas , bash
вы должны использовать, ((...))
чтобы делать арифметику над expr
или let
для удобочитаемости.
Для переносимости используйте ответ$((...))
типа @Bernhard .
let
. Он не является более стандартным или переносимым, чем (( a = 3 * (2 + 1) ))
(оба получены ksh
и доступны только в ksh, bash и zsh), и его менее разборчиво или легко процитировать. Используйте, a=$((3 * (2 + 1)))
чтобы быть портативным.
((a = 3 * (2 + 1) ))
, другая для переносимости a=$((3 * (2 + 1)))
), так что это не примечание против вас или вашего ответа, а против того, чтобы он был выбранным ответом и лучший бомбардир.
a=1 $[a+2]
или a=1 b=2 $[a+b]
. Их причина, чтобы избежать этого синтаксиса?
Вместо этого вы можете использовать арифметическое расширение.
echo "$(( 3 * ( 2 + 1 ) ))"
9
По моему личному мнению, это выглядит немного лучше, чем использование expr
.
Из man bash
Арифметическое расширение Арифметическое расширение позволяет оценить арифметическое выражение и заменить результат. Формат для арифметического расширения:
$((expression))
Выражение обрабатывается так, как если бы оно было в двойных кавычках, но двойные кавычки в скобках специально не обрабатываются. Все токены в выражении подвергаются раскрытию параметров, расширению строк, подстановке команд и удалению кавычек. Арифметические разложения могут быть вложенными.
Оценка проводится в соответствии с правилами, перечисленными ниже в разделе АРИФМЕТИЧЕСКАЯ ОЦЕНКА. Если выражение недопустимо, bash печатает сообщение, указывающее сбой, и подстановка не происходит.
Нет смысла использовать expr
арифметику в современных оболочках.
POSIX определяет $((...))
оператор расширения. Таким образом, вы можете использовать это во всех POSIX-совместимых оболочках ( sh
всех современных Unix-лайков, dash, bash, yash, mksh, zsh, posh, ksh ...).
a=$(( 3 * (2 + 1) ))
a=$((3*(2+1)))
ksh
также представил let
встроенную функцию, которой передается то же самое арифметическое выражение, не расширяется во что-то, но возвращается состояние выхода, основанное на том, разрешает ли выражение значение 0 или нет, как в expr
:
if let 'a = 3 * (2 + 1)'; then
echo "$a is non-zero"
fi
Однако, поскольку цитирование делает его неловким и не очень разборчивым (не в такой же степени, как, expr
конечно), ksh
также введена ((...))
альтернативная форма:
if (( a = 3 * (2 + 1) )) && (( 3 > 1 )); then
echo "$a is non-zero and 3 > 1"
fi
((a+=2))
который намного более разборчивый и должен использоваться вместо этого.
let
и ((...))
доступны только в ksh
, zsh
и bash
. $((...))
Синтаксис должен быть предпочтительным , если портативность для других оболочек необходима, expr
требуется только для предварительного POSIX Борн-подобных оболочек (обычно Bourne оболочки или ранних версий Almquist оболочки).
На фронте не-Борна есть несколько оболочек со встроенным арифметическим оператором:
csh
/ tcsh
(фактически первая оболочка Unix со встроенной арифметической оценкой):
@ a = 3 * (2 + 1)
akanga
(на основании rc
)
a = $:'3 * (2 + 1)'
Как следует из истории, оригинальная версия оболочки Almquist, опубликованная в usenet в 1989 году, имела expr
встроенную функцию (фактически объединенную с test
), но позже была удалена.
: $((a = a*2))
?
$((...))
такие как zsh, ksh93 или yash.
expr
это внешняя команда, это не специальный синтаксис оболочки. Поэтому, если вы хотите expr
видеть специальные символы оболочки, вам нужно защитить их от разбора оболочки, заключив их в кавычки. Кроме того, expr
необходимо, чтобы каждый номер и оператор передавались как отдельный параметр. Таким образом:
expr 3 \* \( 2 + 1 \)
Если вы не работаете над антикварной системой Unix 1970-х или 1980-х годов, причин для использования очень мало expr
. В старые времена в оболочках не было встроенного способа выполнения арифметики, и expr
вместо этого приходилось вызывать утилиту. Все оболочки POSIX имеют встроенную арифметику через синтаксис арифметического расширения .
echo "$((3 * (2 + 1)))"
Конструкция $((…))
расширяется до результата арифметического выражения (записанного в десятичной форме). Bash, как и большинство оболочек, поддерживает только целочисленную арифметику по модулю 2 64 (или по модулю 2 32 для более старых версий bash и некоторых других оболочек на 32-разрядных машинах).
Bash предлагает дополнительный удобный синтаксис, когда вы хотите выполнить присваивания или проверить, равно ли выражение 0, но не заботитесь о результате. Эта конструкция также существует в ksh и zsh, но не в простой sh.
((x = 3 * (2+1)))
echo "$x"
if ((x > 3)); then …
В дополнение к целочисленной арифметике, expr
предлагает несколько функций для работы со строками. К ним также относятся функции оболочек POSIX, за исключением одного: expr STRING : REGEXP
проверяет, соответствует ли строка указанному регулярному выражению. Оболочка POSIX не может сделать это без внешних инструментов, но bash может с [[ STRING =~ REGEXP ]]
(с другим синтаксисом регулярных выражений - expr
это классический инструмент и использует BRE, bash использует ERE).
Если вы не поддерживаете сценарии, которые работают на 20-летних системах, вам не нужно знать, что expr
когда-либо существовало. Используйте арифметику оболочки.
expr foo : '\(.\)'
также делает извлечение текста. bash
«S BASH_REMATCH
достигает что - то подобное. Он также выполняет сравнение строк, чего [
не делает POSIX (хотя можно представить способы его использования sort
).
Используйте скобки с кавычками:
expr 3 '*' '(' 2 '+' 1 ')'
9
Кавычки не позволяют bash интерпретировать скобки как синтаксис bash.
expr
командной строке должны быть разделены пробелами; так; например, expr 3 "*" "(2" "+" "1)"
не будет работать . (Кроме того, кстати, вам, вероятно, не нужно цитировать +
.)
while
и [[
они синтаксис так. Если бы они были ключевыми словами, они не были бы интерпретированы как таковые в аргументах команды. Вам нужны кавычки, чтобы bash не анализировал их, а вместо этого видел строковый литерал.