Tentativa de atribuição a não variável?

6

Podemos usar operações aritméticas dentro da função de script de shell:

function mess
{
   if (( "$1" > 0 )) ; then
      total=$1
   else
      total=100
   fi
   tail -$total /var/adm/messages | more
}

Eu tento fazer essas operações aritméticas nos argumentos de função:

#!/bin/bash
byte="Bytes"
kilo="KB"
mega="MB"
giga="GB"
function bytesToUnites() {
if (( "$1" < 1000 )) 
then
    echo $1" "$byte
elif (( $1 < 1000000 ))
then
    let $1/=1000
    echo $1" "$kilo
fi
}

bytesToUnites 28888

Mas recebo este erro:

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

Como posso corrigir isso?

    
por user79550 03.08.2014 / 02:05

3 respostas

6

O problema é que você está tentando realizar substituição de parâmetro ao preceder o primeiro nome do parâmetro posicional com $ .

Você pode realizar o que quiser da seguinte forma:

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

Tanto quanto eu posso dizer, você não pode usar o parâmetro posicional diretamente dizendo:

let 1/=1000

porque isso seria um erro de sintaxe.

Por acaso, na sua mensagem de erro, posso ver que $1 foi definido como 28888 . Você deve notar que Bash não faz aritmética de ponto flutuante. Você encontrará arg definido como 28 (o quociente da divisão inteira de 28888 por 1000) em vez de 28.888. Por favor, veja este maravilhoso Q & Um sobre como fazer aritmética de ponto flutuante em scripts.

    
por 03.08.2014 / 02:13
3

A única maneira de atribuir valores a parâmetros posicionais em bash é através do set builtin:

set a b

atribui a a $1 e b a $2 (observe que ela redefine toda a lista de parâmetros posicionais, portanto $3 , $4 ... são perdidos).

Então, aqui você pode fazer:

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

Para atribuir o valor de $1 dividido por 1000 a $1 .

Por outro lado, com zsh (um shell mais avançado do tipo Bourne, que não faz parte do projeto GNU, encontrado em todos os Unices, embora não seja padrão), você pode atribuir parâmetros posicionais individuais como:

1=$(($1 / 1000))

Ou:

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

Ou:

(( argv[1] /= 1000 ))

( $argv é uma matriz especial ligada aos parâmetros posicionais lá)

Você ainda não pode fazer:

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

embora.

zsh também suporta aritmética de ponto flutuante, assim você pode fazer:

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

(o uso de uma constante de ponto flutuante (1000.) força a aritmética de ponto flutuante).

Você pode querer exibi-lo como:

printf "%.2f$kilo\n" $1
    
por 03.08.2014 / 10:51
0

Para meus dois centavos, recomendo que você use o % modulo. Você pode simplesmente subir a lista de unidades e salvar seu restante a cada etapa. Aqui:

(   
    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
)

OUTPUT

8321gb
140mb
454kb
417b
    
por 04.08.2014 / 02:32