Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

We can use arithmetic operations inside shell script function:

function mess
   if (( "$1" > 0 )) ; then
   tail -$total /var/adm/messages | more

I try to do this arithmetic operations on the function args:

function bytesToUnites() {
if (( "$1" < 1000 )) 
    echo $1" "$byte
elif (( $1 < 1000000 ))
    let $1/=1000
    echo $1" "$kilo

bytesToUnites 28888

But I get this error:

line 12: let: 28888/=1000: attempted assignment to non-variable (error token is "/=1000")
28888 KB

How can I fix this?

share|improve this question
Your placement of " characters is not optimal. In almost all cases, expansion of $var should be inside ", not outside of it. So for example echo $1" "$byte is bad, echo "$1 $byte" is good. – kasperd Aug 3 '14 at 10:38
up vote 6 down vote accepted

The problem is that you are attempting to perform parameter substitution by preceding the first positional parameter name with $.

You can accomplish what you want like so:

elif [ $1 -lt 1000000 ]
    let arg/=1000
    echo $arg" "$kilo

As far as I can tell, you can't use the positional parameter directly by saying:

let 1/=1000

because this would be a syntax error.

Incidentally, from your error message, I can see that $1 was set to 28888. You should note that Bash doesn't do floating point arithmetic. You will find arg set to 28 (the quotient of integer division of 28888 by 1000) instead of 28.888. Please see this wonderful Q&A on how to do floating point arithmetic in scripts.

share|improve this answer
Thanks I wanted to upvote it but I can't – user79550 Aug 3 '14 at 0:16
@user79550 No worries. If the answer properly solves your problem, consider accepting it (click the tick button under the vote buttons) so that others know this question is solved. – Joseph R. Aug 3 '14 at 0:19

The only way to assign values to positional parameters in bash is via the set builtin:

set a b

assigns a to $1 and b to $2 (note that it resets the whole positional parameter list, so $3, $4... are lost).

So here, you could do:

set -- "$(($1 / 1000))"

To assign the value of $1 divided by 1000 to $1.

By contrast, with zsh (a more advanced Bourne-like shell, not part of the GNU project, found on all Unices though often not by default), you can assign individual positional parameters like:

1=$(($1 / 1000))


argv[1]=$(($1 / 1000))


(( argv[1] /= 1000 ))

($argv is a special array tied to the positional parameters there)

You still cannot do:

let 1/=1000
(( 1/=1000 ))


zsh also supports floating point arithmetics, so you can do:

((argv[1] /= 1000.))

(the use a of a floating point constant (1000.) forces floating point arithmetic).

You may want to display it like:

printf "%.2f$kilo\n" $1
share|improve this answer
I have tried printf "%.2f$kilo\n" $1 as you suggested but it printed 28.00 instead of 28.88 @Stéphane Chazelas – user79550 Aug 3 '14 at 12:57
@user79550, in zsh? After ((argv[1] /= 1000.)) ? – Stéphane Chazelas Aug 3 '14 at 15:46
Is there other ways that I can get the floating point without zsh – user79550 Aug 3 '14 at 16:38
@user79550, you can call any other application (shell or not) that can do floating point arithmetic from your dumb shell (zsh, ksh93, bc, dc, awk, perl, php... see unix.stackexchange.com/questions/40786/…) – Stéphane Chazelas Aug 3 '14 at 16:41

For my two cents, I'll recommend you use the % modulo. You can just walk up the unit list and save your remainder every step. Here:

    gb=$(((mb=(kb=1024*(b=1))*kb)*kb))                 #define units 
    set -- 8934752983457                               #your $1 - just a random test
    for u in '' k m g                                  #this part is neat
    do  [ $((c=$1/${u}b)) -ge 1 ] || break             #math eval varnames
        [ "$u" != g ] && c=$(($c%$kb))                 #if not yet g only save %
        set -- $(($1-$c)) "$c${u}b${2:+.$2}"           #decrement $1 - build $2
    done ; shift                                       #done - toss $1
    IFS=. ; printf %s\\n $*                            #split $2 andd print


share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.