86

You can use the arithmetic expansion instead. echo "$(( 3 * ( 2 + 1 ) ))" 9 In my personal opinion, this looks a bit nicer than using expr. From man bash Arithmetic Expansion Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is: $((expression)) ...


47

Another way to use let bash builtin: $ let a="3 * (2 + 1)" $ printf '%s\n' "$a" 9 Note As @Stéphane Chazelas pointed out, in bash you should use ((...)) to do arithmetic over expr or let for legibility. For portability, use $((...)) like @Bernhard answer.


41

There's no reason to be using expr for arithmetic in modern shells. POSIX defines the $((...)) expansion operator. So you can use that in all POSIX compliant shells (the sh of all modern Unix-likes, dash, bash, yash, mksh, zsh, posh, ksh...). a=$(( 3 * (2 + 1) )) a=$((3*(2+1))) ksh also introduced a let builtin which is passed the same kind of arithmetic ...


40

I'm getting 2 from your code. Nevertheless, you can use the same technique for any variable or number: local start=1 (( start++ )) or (( ++start )) or (( start += 1 )) or (( start = start + 1 )) or just local start=1 echo $(( start + 1 )) etc.


36

The [ command/shell builtin has comparison tests, so you can just do if [ "$REPLY" -ge 1 ] && [ "$REPLY" -le 32 ]; then REPLY=-2; elif [ "$REPLY" -ge 33 ] && [ "$REPLY" -le 48 ]; then REPLY=-1; fi where -ge means greater-or-equal-to (and so on). The [ command is just a command, not special syntax (it's actually the same as test: check out ...


32

Rounding floating point numbers What does "rounding a floating point number" mean? That's easy, obviously... Where's my math book from school... No, we already know nothing related to floating point numbers is easy: For a start, there are multiple rounding modes: Rounding upwards? Rounding downwards? Rounding to zero? Rounding to nearest - ties ...


32

The problem is in cases where the content of $x has not been sanitized and contains data that could potentially be under the control of an attacker in cases that shell code may end up being used in a privilege escalation context (for instance a script invoked by a setuid application, a sudoers script or used to process off-the-network data (CGI, DHCP hook...)...


32

Bash uses intmax_t variables for arithmetic. On your system these are 64 bits in length, so: $ echo $((1<<62)) 4611686018427387904 which is 100000000000000000000000000000000000000000000000000000000000000 in binary (1 followed by 62 0s). Shift that again: $ echo $((1<<63)) -9223372036854775808 which is ...


32

The leading 0 causes Bash to interpret the value as an octal value; 012 octal is 10 decimal, so you get 11. To force the use of decimal, add 10# (as long as the number has no leading sign): BN=10#$(cat Build.number) echo $((++BN)) > Build.number To print the number using at least three digits, use printf: printf "%.3d\n" $((++BN)) > Build.number


30

In a thread on the GNU bash mailing list, it says that the $[ syntax was an early syntax that was deprecated in favor of $((, since the latter was already used by the Korn shell. According to this site, the manual for bash 3.2.48 contained a reference to the $[ syntax. So presumably this reference had been removed in 3.2.51.


27

You can find old bash source here. In particular I downloaded bash-1.14.7.tar.gz. In the documentation/bash.txt you will find: Arithmetic Expansion Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. There are two formats for arithmetic expansion: $[expression] $((expression)) The ...


22

Bash doesn't have an -= assignment operator in the main shell syntax (arithmetic context is different, see below). That is to say, while you can use = to assign to variables, and += to append to non-integer variables, or add to integer variables, there's no -=, *= etc. to go with them. The situation is the same in Ksh, where Bash's syntax is borrowed from (...


21

No. Bash cannot perform floating point arithmetic natively. This is not what you're looking for but may help someone else: Alternatives bc bc allows floating point arithmetic, and can even convert whole numbers to floating point by setting the scale value. (Note the scale value only affects division within bc but a workaround for this is ending any ...


19

Shortcut Alt-c (bash) With bash, using the readline utility, we can define a key sequence to place the word calc at the start and enclose the text written so far into double quotes: bind '"\ec": "\C-acalc \"\e[F\""' Having executed that, you type 23 + 46 * 89 for example, then Alt-c to get: calc "23 + 46 * 89" Just press enter and the math will be ...


19

Bash arithmetic uses signed numbers. So the quick answer would be: ((MAX=(1<<63)-1)) But since you want your script to not know about the bitness of the system it's running on, then let's keep going. Brute force would be, keep adding 1 in a loop, until you hit the point where it will overflow unto a negative number. But that could take years! :-) A ...


18

expr is an external command, it is not special shell syntax. Therefore, if you want expr to see shell special characters, you need to protect them from shell parsing by quoting them. Furthermore, expr needs each number and operator to be passed as a separate parameter. Thus: expr 3 \* \( 2 + 1 \) Unless you're working on an antique unix system from the ...


18

#!/bin/sh EPOCH='jan 1 1970' sum=0 for i in 00:03:34 00:00:35 00:12:34 do sum="$(date -u -d "$EPOCH $i" +%s) + $sum" done echo $sum|bc date -u -d "jan 1 1970" +%s gives 0. So date -u -d "jan 1 1970 00:03:34" +%s gives 214 secs.


18

bash treats constants that start with 0 as octal numbers in its arithmetic expressions, so 011 is actually 9. That's actually a POSIX requirement. Some other shells like mksh or zsh ignore it (unless in POSIX compliant mode) as it gets in the way far more often than it is useful. With ksh93, BN=011; echo "$(($BN))" outputs 9, but echo "$((BN))" outputs 11....


17

Given that printf 'eth0 Download rate: %s B/s\n' "$((eth0_rx2-eth0_rx1))" is giving you the correct value, as long as integer arithmetic is good enough, you’ve got your answer: $((eth0_rx2-eth0_rx1)), i.e. shell arithmetic. Many shells, notably Bash, use 64-bit integers, even on 32-bit platforms. Thus: eth0_diff=$((eth0_rx2 - eth0_rx1)) ... ...


16

Historically, the test command existed first (at least as far back to Unix Seventh Edition in 1979). It used the operators = and != to compare strings, and -eq, -ne, -lt, etc. to compare numbers. For example, test 0 = 00 is false, but test 0 -eq 00 is true. I don't know why this syntax was chosen, but it may have been to avoid using < and >, which the ...


16

In Bash, arithmetic evaluation is done inside (( )), e.g. ((i=i+3)). From Bash's man page (man bash), ((expression)) The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. Both -= and += are documented in the ARITHMETIC EVALUATION section, along with = *= /= %= <<= >>= &= ^= |=, and all work as you ...


15

No need for bash, plain sh will do as well: #! /bin/sh - IFS=+; echo "$(($*))" $* in POSIX shells, expands to the list of positional parameters (in this case, the arguments to the script) separated by the first character of $IFS (or space if $IFS is unset or nothing if $IFS is empty). $((...)) is the shell internal arithmetic expansion operator (note that ...


15

You could simply say: ((REPLY>=1 && REPLY<=32)) && REPLY=-2 ((REPLY>=33 && REPLY<=48)) && REPLY=-1 Quoting from the manual: ((...)) (( expression )) The arithmetic expression is evaluated according to the rules described below (see Shell Arithmetic). If the value of the expression is non-zero, the ...


15

In bash, numbers with leading zeros are considered as octal. To force bash to consider them as decimal, you can add a 10# prefix: next_number=$(printf %06d "$((10#$current_number + 1))") Or with bash 3.1 or above, to avoid the forking: printf -v next_number %06d "$((10#$current_number + 1))" (note that it doesn't work for negative numbers as 10#-010 is ...


15

To create the table with a single call to awk: $ awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' data data foo 10 10% bar 20 20% oof 50 50% rab 20 20% How it works The file data is provided as an argument to awk twice. Consequently, it will be read twice, the first time to get the total, which is ...


14

Use parenthesis with quotes: expr 3 '*' '(' 2 '+' 1 ')' 9 The quotes prevent bash from interpreting the parenthesis as bash syntax.


13

To elaborate on bollovan's answer... There is no >= or <= comparison operator for strings. But you could use them with the ((...)) arithmetic command to compare integers. You can also use the other string comparison operators (==, !=, <, >, but not =) to compare integers if you use them inside ((...)). Examples Both [[ 01 -eq 1 ]] and (( 01 ==...


13

bash does not understand floating point numbers. Quoting bash manual page, section ARITHMETIC EVALUATION: Evaluation is done in fixed-width integers […]. So ((3 < 4)) or ((3 < 2)) are actually correct arithmetic expressions. You can type the following: $ echo "$((3 < 4)) -- $((3 < 2))" output: 1 -- 0 But $ echo $((3.3 < 3.6)) will ...


13

Inside [[...]] < is for string comparison. So [[ 3.56 < 2.90 ]] or [[ (3.56 < 2.90) ]] or [[ ((3.56 < 2.90)) ]] or [[ (((3.56 < 2.90))) ]]... is just comparing the 3.56 string with the 2.90 string lexically (and lexically, 3 is greater than 10 for instance). For integer comparison, it's [[ 3 -lt 2 ]] or (( 3 < 2 )). If you want floating ...


Only top voted, non community-wiki answers of a minimum length are eligible