51 votes

Comment arrondir les décimales en utilisant bc dans bash ?

Un exemple rapide de ce que je veux en utilisant un script bash :

#!/bin/bash
echo "Insérez le prix que vous souhaitez calculer :"
read float
echo "Voici le prix sans taxes :"
echo "scale=2; $float/1.18" |bc -l
read -p "Appuyez sur une touche pour continuer..."
bash scriptname.sh

En supposant que le prix est 48.86 La réponse sera : 41.406779661 (41.40 en réalité car j'utilise scale=2;)

Ma question est : Comment arrondir le deuxième décimal pour afficher la réponse de cette manière : 41.41

1voto

Chris Reid Points 111

J'ai dû calculer la durée totale d'une collection de fichiers audio.

Donc j'ai dû:

A. obtenir la durée de chaque fichier (non montré)

B. additionner toutes les durées (elles étaient chacune en NNN.NNNNNN (fp) secondes )

C. séparer les heures, minutes, secondes, sous-secondes.

D. produire une chaîne de caractères HR:MIN:SEC:IMAGES, où l'image = 1/75 sec.

(Les images proviennent du code SMPTE utilisé dans les studios.)


A: utiliser ffprobe et analyser la ligne de durée en un nombre fp (non montré)

B:

 # les additionner comme une série de chaînes séparées par "+" et les envoyer à bc

arr=( "${total[@]}" )  # copier le tableau

# IFS est "Internal Field Separator"
# le * dans arr[*] signifie "tous les éléments de arr séparés par IFS" 
# doit avoir été fait pour cela
IFS='+' sum=$(echo "scale=3; ${arr[*]} "| bc -l)# (-l= libmath pour fp)
echo $sum 

C:

# soustraire chaque montant de temps de tt et le stocker    
tt=$sum   # tt est une variable d'exécution (fp)

hrs=$(echo "$tt / 3600" | bc)

tt=$(echo "$tt - ( $hrs * 3600 )" | bc )

min=$(echo "$tt / 60" | bc )

tt=$(echo "$tt - ($min *60)" | bc )

sec=$(echo "$tt/1" | bc )

tt=$(echo "$tt - $sec" | bc )

frames=$(echo "$tt * 75"  | bc ) # 75 images /sec 
frames=$(echo "$frames/1" | bc ) # tronquer au nombre entier supérieur

D:

#convertir au format correct avec printf (fonction intégrée de bash)        
hrs=$(printf "%02d\n" $hrs)  # format 1 -> 01 

min=$(printf "%02d\n" $min)

sec=$(printf "%02d\n" $sec)

frames=$(printf "%02d\n" $frames)

timecode="$hrs:$min:$sec:$frames"

# timecode "01:13:34:54"

0voto

sjas Points 313
bc() {
        while :
        do
                while IFS='$\n' read i
                do
                        /usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/'
                done
        done
}

translation:

bc() {
        while :
        do
                while IFS='$\n' read i
                do
                        /usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/'
                done
        done
}

0voto

Vous pouvez utiliser awk, aucun tuyau nécessaire:

$> PRICE=48.86
$> awk -vprice=$PRICE "BEGIN{printf(\"%.2f\n\",price/1.18+0.005)}"
41.41

Définissez le prix préalablement avec la variable d'environnement PRICE=.

  • Ensuite, appelez awk - $PRICE ira dans awk en tant que variable awk price.

  • Il est ensuite arrondi au centième supérieur avec +.005.

  • L'option de format d'impression %.2f limite l'échelle à deux décimales.

Si vous devez faire cela souvent, cette méthode est beaucoup plus efficace que la réponse sélectionnée:

time for a in {1..1000}; do echo $(round 48.86/1.18 2) > /dev/random; done
real    0m8.945s
user    0m6.067s
sys 0m4.277s

time for a in {1..1000}; do awk -vprice=$PRICE "BEGIN{printf(\"%.2f\n\",price/1.18+0.005)}">/dev/random; done
real    0m2.628s
user    0m1.462s
sys 0m1.275s

0voto

Alex_123XYZ Points 1

PRINTF PAS FIABLE :

La méthode printf est très pratique, facile à utiliser et est répertoriée dans de nombreux tutoriels.

Cependant, si vous avez codé en dur un point décimal, sachez que votre code risque probablement d'échouer si utilisé dans l'un des nombreux pays utilisant une virgule comme séparateur.

Un nombre surprenant de pays utilisent en réalité cela, et beaucoup d'entre eux sont en Europe. Probablement autant que ceux utilisant un point. Selon Wikipedia > Decimal_separator, la virgule est mentionnée comme une directive ISO/IEC ...

Voici ce qui se passe si votre ordinateur est configuré pour utiliser les virgules dans son système numérique :

printf %.2f 573,5489   

573,55

mais

printf %.2f 573.5489   

printf: 573.5489 : nombre invalide

Comment contourner cela ?

Utiliser 'bc' en est une manière. En soi, simplement avec scale=n. Il n'est pas nécessaire de le rediriger comme dans certains exemples. N'oubliez pas que scale fonctionne uniquement avec la division et pour diviser votre somme d'entrée par un. Consultez la réponse de @user525061

L'autre option, surtout si vous avez déjà du code utilisant la méthode printf, pourrait être de changer la localisation de votre session shell en utilisant 'export'.

Essayez :

export LC_NUMERIC=C

Mais cela va à l'encontre de la simplicité de printf....

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X