web-dev-qa-db-fra.com

Comment puis-je ajouter des nombres dans un script bash

J'ai ce script bash et j'ai eu un problème à la ligne 16. Comment puis-je prendre le résultat précédent de la ligne 15 et l'ajouter à la variable de la ligne 16?

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        num= $num + $metab   (line16)
    done
    echo "$num"
 done
498
Nick

Pour les entiers :

  • Utilisez expansion arithmétique : $((EXPR))

    num=$((num1 + num2))
    num=$(($num1 + $num2))       # also works
    num=$((num1 + 2 + 3))        # ...
    num=$[num1+num2]             # old, deprecated arithmetic expression syntax
    
  • Utilisation de l'utilitaire externe expr. Notez que cela n’est nécessaire que pour les systèmes très anciens.

    num=`expr $num1 + $num2`     # whitespace for expr is important
    

Pour la virgule flottante :

Bash ne supporte pas directement cela, mais il y a quelques outils externes que vous pouvez utiliser:

num=$(awk "BEGIN {print $num1+$num2; exit}")
num=$(python -c "print $num1+$num2")
num=$(Perl -e "print $num1+$num2")
num=$(echo $num1 + $num2 | bc)   # whitespace for echo is important

Vous pouvez également utiliser la notation scientifique (par exemple: 2.5e+2)


Pièges courants :

  • Lorsque vous définissez une variable, vous ne pouvez pas utiliser d'espaces de part et d'autre de =, sinon le Shell sera obligé d'interpréter le premier mot comme nom de l'application à exécuter (par exemple: num= ou num)

    num= 1num =2

  • bc et expr attendent chaque numéro et chaque opérateur comme argument séparé. Les espaces sont donc importants. Ils ne peuvent pas traiter des arguments tels que 3++4.

    num=`expr $num1+ $num2`

878
Karoly Horvath

Utilisez le développement arithmétique $(( )).

num=$(( $num + $metab ))

Voir http://tldp.org/LDP/abs/html/arithexp.html pour plus d'informations.

88
Steve Prentice

Il y a mille et une façons de le faire. En voici une qui utilise dc:

dc <<<"$num1 $num2 + p"

Mais si c'est trop bas pour vous (ou que la portabilité compte), vous pourriez dire

echo $num1 $num2 + p | dc

Mais peut-être êtes-vous de ceux qui pensent que RPN est dégoûtant et étrange; ne t'inquiète pas! bc est là pour vous:

bc <<< "$num1 + $num2"
echo $num1 + $num2 | bc

Cela dit, vous pourriez apporter des améliorations indépendantes à votre script.

#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do
    for j in output-$i-* ; do # for can glob directly, no need to ls
            echo "$j"

             # grep can read files, no need to use cat
            metab=$(grep EndBuffer "$j" | awk '{sum+=$2} END { print sum/120}')
            num=$(( $num + $metab ))
    done
    echo "$num"
done

MODIFIER:

Comme décrit dans BASH FAQ 022 , bash ne supporte pas nativement les nombres à virgule flottante. Si vous devez additionner des nombres en virgule flottante, l'utilisation d'un outil externe (tel que bc ou dc) est requise.

Dans ce cas, la solution serait

num=$(dc <<<"$num $metab + p")

Pour additionner des nombres à virgule flottante dans num.

27
Sorpigal

En bash,

 num=5
 x=6
 (( num += x ))
 echo $num   # ==> 11

Notez que bash ne peut gérer que l'arithmétique entière, donc si votre commande awk retourne une fraction, vous voudrez la refondre: voici votre code un peu réécrit pour faire tous les calculs dans awk.

num=0
for ((i=1; i<=2; i++)); do      
    for j in output-$i-*; do
        echo "$j"
        num=$(
           awk -v n="$num" '
               /EndBuffer/ {sum += $2}
               END {print n + (sum/120)}
           ' "$j"
        )
    done
    echo "$num"
done
22
glenn jackman

J'oublie toujours la syntaxe alors je viens sur Google, mais je ne trouve jamais celle que je connais bien: P. C’est le plus propre et le plus fidèle à ce que j’attendais dans d’autres langues.

i=0
((i++))

echo $i;
16
ssshake

J'aime aussi beaucoup cette méthode, moins d'encombrement:

count=$[count+1]
15
unixball
 #!/bin/bash
read X
read Y
echo "$(($X+$Y))"
11
Amarjeet Singh

Vous devez déclarer la métab comme un entier, puis utiliser l'évaluation arithmétique.

declare -i metab num
...
num+=metab
...

Pour plus d'informations, voir https://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html#Shell-Arithmetic

8
Pavel

Une autre manière portable POSIX conforme à faire dans bash, qui peut être définie comme une fonction dans .bashrc pour tous les opérateurs arithmétiques de convenance.

addNumbers () {
    local IFS='+'
    printf "%s\n" "$(( $* ))"
}

et appelez-le simplement en ligne de commande en tant que,

addNumbers 1 2 3 4 5 100
115

L'idée est d'utiliser Input-Field-Separator (IFS) , une variable spéciale dans bash utilisée pour la division de Word après le développement et la division de lignes en mots. La fonction modifie la valeur localement pour utiliser le caractère de fractionnement de Word comme opérateur de somme +.

Rappelez-vous que IFS est modifié localement et ne PAS prend effet sur le comportement par défaut IFS en dehors de la portée de la fonction. Un extrait de la page man bash,

Le shell traite chaque caractère de l’IFS comme un séparateur et divise les résultats des autres extensions en mots sur ces caractères. Si IFS n'est pas défini ou si sa valeur est exactement la valeur par défaut, les séquences de, et au début et à la fin des résultats des extensions précédentes sont ignorées, et toute séquence de caractères IFS ne figurant pas au début ou à la fin sert à délimiter mots.

"$(( $* ))" représente la liste des arguments passés pour être scindés par +, puis la valeur de somme est sortie à l'aide de la fonction printf. La fonction peut être étendue pour ajouter également une portée pour d'autres opérations arithmétiques.

6
Inian
#!/bin/bash

num=0
metab=0

for ((i=1; i<=2; i++)); do      
    for j in `ls output-$i-*`; do
        echo "$j"

        metab=$(cat $j|grep EndBuffer|awk '{sum+=$2} END { print sum/120}') (line15)
        let num=num+metab (line 16)
    done
    echo "$num"
done
2
Milen John Thomas