Commande shell pour additionner des entiers, un par ligne?

867

Je recherche une commande qui acceptera (en entrée) plusieurs lignes de texte, chaque ligne contenant un seul entier, et produira la somme de ces entiers.

En guise de contexte, j'ai un fichier journal qui comprend des mesures de synchronisation. Grâce à la recherche des lignes pertinentes et un peu de sedreformatage, je peux répertorier tous les timings dans ce fichier. Je voudrais calculer le total. Je peux diriger cette sortie intermédiaire vers n'importe quelle commande afin de faire la somme finale. Je l'ai toujours utilisé exprdans le passé, mais à moins qu'il ne fonctionne en mode RPN, je ne pense pas qu'il va y faire face (et même alors, ce serait délicat).

Comment obtenir la somme des nombres entiers?

Andrzej Doyle
la source
2
Ceci est très similaire à une question que j'ai posée il y a un moment: stackoverflow.com/questions/295781/…
An̲̳̳drew
5
J'aime beaucoup cette question car il existe de nombreuses réponses correctes (ou du moins fonctionnelles).
Francisco Canedo
Cette question ressemble à un problème pour le golf de code. codegolf.stackexchange.com :)
Gordon Bean

Réponses:

1322

Un peu d'awk devrait le faire?

awk '{s+=$1} END {print s}' mydatafile

Remarque: certaines versions de awk ont ​​des comportements étranges si vous souhaitez ajouter quelque chose dépassant 2 ^ 31 (2147483647). Voir les commentaires pour plus d'informations. Une suggestion est d'utiliser printfplutôt que print:

awk '{s+=$1} END {printf "%.0f", s}' mydatafile
Paul Dixon
la source
7
Il y a beaucoup d'amour awk dans cette pièce! J'aime la façon dont un simple script comme celui-ci pourrait être modifié pour ajouter une deuxième colonne de données simplement en changeant le $ 1 en $ 2
Paul Dixon
2
Il n'y a pas de limite pratique, car il traitera l'entrée comme un flux. Donc, s'il peut gérer un fichier de lignes X, vous pouvez être sûr qu'il peut gérer X + 1.
Paul Dixon
4
J'ai écrit une fois un processeur de liste de diffusion rudimentaire avec un script awk exécuté via l'utilitaire de vacances. Bon temps. :)
LS
2
vient de l'utiliser pour un script: compter toutes les pages des documents:ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
moutons volants
8
Attention, cela ne fonctionnera pas avec des nombres supérieurs à 2147483647 (c'est-à-dire 2 ^ 31), car awk utilise une représentation d'entier signé 32 bits. Utilisez awk '{s+=$1} END {printf "%.0f", s}' mydatafileplutôt.
Giancarlo Sportelli
665

Coller fusionne généralement les lignes de plusieurs fichiers, mais il peut également être utilisé pour convertir des lignes individuelles d'un fichier en une seule ligne. L'indicateur de délimitation vous permet de passer une équation de type x + x à bc.

paste -s -d+ infile | bc

Alternativement, lorsque vous canalisez depuis stdin,

<commands> | paste -s -d+ - | bc
radoulov
la source
1
Très agréable! J'aurais mis un espace avant le "+", juste pour m'aider à mieux l'analyser, mais c'était très pratique pour canaliser certains numéros de mémoire via paste & bc.
Michael H.
73
Beaucoup plus facile à mémoriser et à taper que la solution awk. Notez également que vous pastepouvez utiliser un tiret -comme nom de fichier - ce qui vous permettra de diriger les nombres de la sortie d'une commande vers la sortie standard de la pâte sans avoir besoin de créer d'abord un fichier:<commands> | paste -sd+ - | bc
George
19
J'ai un fichier avec 100 millions de numéros. La commande awk prend 21 secondes; la commande coller prend 41 secondes. Mais bon de rencontrer quand même 'coller'!
Abhi
4
@Abhi: Intéressant: DI suppose que cela me prendrait 20s pour comprendre la commande awk, donc ça égalise jusqu'à ce que j'essaie 100 millions et un nombre: D
Mark K Cowan
6
@George Vous pouvez cependant laisser de côté le -. (C'est utile si vous souhaitez combiner un fichier avec stdin).
Alois Mahdal
128

La version monoligne en Python:

$ python -c "import sys; print(sum(int(l) for l in sys.stdin))"
dF.
la source
Au-dessus d'une ligne ne fonctionne pas pour les fichiers dans sys.argv [], mais celui-ci fait stackoverflow.com/questions/450799/…
jfs
Certes, l'auteur a dit qu'il allait diriger la sortie d'un autre script dans la commande et j'essayais de la rendre aussi courte que possible :)
dF.
39
La version plus courte seraitpython -c"import sys; print(sum(map(int, sys.stdin)))"
jfs
4
J'adore cette réponse pour sa facilité de lecture et sa flexibilité. J'avais besoin de la taille moyenne des fichiers inférieurs à 10 Mo dans une collection de répertoires et je l'ai modifiée comme find . -name '*.epub' -exec stat -c %s '{}' \; | python -c "import sys; nums = [int(n) for n in sys.stdin if int(n) < 10000000]; print(sum(nums)/len(nums))"
Paul Whipp
1
Vous pouvez également filtrer les non-nombres si vous avez du texte mélangé:import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Granitosaurus
91

Je mettrais un gros AVERTISSEMENT sur la solution couramment approuvée:

awk '{s+=$1} END {print s}' mydatafile # DO NOT USE THIS!!

c'est parce que dans ce formulaire, awk utilise une représentation d'entier signé 32 bits: il débordera pour les sommes qui dépassent 2147483647 (c'est-à-dire 2 ^ 31).

Une réponse plus générale (pour additionner des entiers) serait:

awk '{s+=$1} END {printf "%.0f\n", s}' mydatafile # USE THIS INSTEAD
Giancarlo Sportelli
la source
Pourquoi printf () aide-t-il ici? Le débordement de l'int aura déjà eu lieu car le code de sommation est le même.
Robert Klemme
9
Parce que le problème est en fait dans la fonction "print". Awk utilise des nombres entiers 64 bits, mais pour une raison quelconque, les donws les mettent à l'échelle 32 bits.
Giancarlo Sportelli
4
Le bug d'impression semble être corrigé, au moins pour awk 4.0.1 et bash 4.3.11, sauf erreur de ma part: echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'montre2147483747
Xen2050
4
L'utilisation de flotteurs introduit juste un nouveau problème: echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'produit1000000000000000000
Patrick
1
Ne devrait-on pas simplement utiliser "% ld" sur les systèmes 64 bits pour que printf ne soit pas tronqué à 32 bits? Comme le souligne @Patrick, les flotteurs ne sont pas une excellente idée ici.
yerforkferchips
78

Bash simple:

$ cat numbers.txt 
1
2
3
4
5
6
7
8
9
10
$ sum=0; while read num; do ((sum += num)); done < numbers.txt; echo $sum
55
Giacomo
la source
2
Un plus petit liner: stackoverflow.com/questions/450799/…
Khaja Minhajuddin
@rjack, où est numdéfini? Je crois en quelque sorte que cela est lié à l' < numbers.txtexpression, mais on ne sait pas comment.
Atcold
66
dc -f infile -e '[+z1<r]srz1<rp'

Notez que les nombres négatifs préfixés par le signe moins doivent être traduits pour dc, car il utilise le _préfixe plutôt que le -préfixe pour cela. Par exemple, via tr '-' '_' | dc -f- -e '...'.

Edit: Puisque cette réponse a obtenu autant de votes "pour l'obscurité", voici une explication détaillée:

L'expression [+z1<r]srz1<rp fait ce qui suit :

[   interpret everything to the next ] as a string
  +   push two values off the stack, add them and push the result
  z   push the current stack depth
  1   push one
  <r  pop two values and execute register r if the original top-of-stack (1)
      is smaller
]   end of the string, will push the whole thing to the stack
sr  pop a value (the string above) and store it in register r
z   push the current stack depth again
1   push 1
<r  pop two values and execute register r if the original top-of-stack (1)
    is smaller
p   print the current top-of-stack

Comme pseudo-code:

  1. Définissez "add_top_of_stack" comme:
    1. Retirez les deux premières valeurs de la pile et ajoutez le résultat
    2. Si la pile a deux ou plusieurs valeurs, exécutez récursivement "add_top_of_stack"
  2. Si la pile a deux ou plusieurs valeurs, exécutez "add_top_of_stack"
  3. Imprimer le résultat, désormais le seul élément restant dans la pile

Pour vraiment comprendre la simplicité et la puissance de dc, voici un script Python fonctionnel qui implémente certaines des commandes de dcet exécute une version Python de la commande ci-dessus:

### Implement some commands from dc
registers = {'r': None}
stack = []
def add():
    stack.append(stack.pop() + stack.pop())
def z():
    stack.append(len(stack))
def less(reg):
    if stack.pop() < stack.pop():
        registers[reg]()
def store(reg):
    registers[reg] = stack.pop()
def p():
    print stack[-1]

### Python version of the dc command above

# The equivalent to -f: read a file and push every line to the stack
import fileinput
for line in fileinput.input():
    stack.append(int(line.strip()))

def cmd():
    add()
    z()
    stack.append(1)
    less('r')

stack.append(cmd)
store('r')
z()
stack.append(1)
less('r')
p()
André Laszlo
la source
2
dc n'est que l'outil de choix à utiliser. Mais je le ferais avec un peu moins d'opérations de pile. Supposaient que toutes les lignes contiennent vraiment un numéro: (echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc.
ikrabbe
5
L'algorithme en ligne: dc -e '0 0 [+?z1<m]dsmxp'. Donc, nous ne sauvegardons pas tous les nombres sur la pile avant le traitement, mais les lisons et les traitons un par un (pour être plus précis, ligne par ligne, car une ligne peut contenir plusieurs nombres). Notez qu'une ligne vide peut mettre fin à une séquence d'entrée.
ruvim
@ikrabbe c'est super. Il peut en fait être raccourci d'un caractère de plus: l'espace dans la sedsubstitution peut être supprimé, car peu importe les dc espaces entre les arguments et les opérateurs. (echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
WhiteHotLoveTiger
58

Avec jq :

seq 10 | jq -s 'add' # 'add' is equivalent to 'reduce .[] as $item (0; . + $item)'
banyan
la source
7
J'aime ça parce que je suppose que c'est tellement clair et court que je pourrais peut-être m'en souvenir.
Alfe
46

Bash pur et court.

f=$(cat numbers.txt)
echo $(( ${f//$'\n'/+} ))
Daniel
la source
9
C'est la meilleure solution car elle ne crée aucun sous-processus si vous remplacez la première ligne par f=$(<numbers.txt).
loentar
1
un moyen d'avoir l'entrée de stdin? comme dans une pipe?
njzk2
@ njzk2 Si vous insérez f=$(cat); echo $(( ${f//$'\n'/+} ))un script, vous pouvez alors diriger n'importe quoi vers ce script ou l'invoquer sans arguments pour une entrée stdin interactive (terminez par Control-D).
mklement0
5
@loentar Le <numbers.txtest une amélioration, mais, dans l'ensemble, cette solution n'est efficace que pour les petits fichiers d'entrée; par exemple, avec un fichier de 1 000 lignes d'entrée, la awksolution acceptée est environ 20 fois plus rapide sur ma machine - et consomme également moins de mémoire, car le fichier n'est pas lu en une seule fois.
mklement0
2
J'avais presque perdu espoir en atteignant celui-ci. Pure bash!
Omer Akhter
37
perl -lne '$x += $_; END { print $x; }' < infile.txt
j_random_hacker
la source
4
Et je les ai rajoutés: "-l" garantit que la sortie est terminée par LF comme les `` backticks du shell et la plupart des programmes s'y attendent, et "<" indique que cette commande peut être utilisée dans un pipeline.
j_random_hacker
Tu as raison. Comme excuse: Chaque personnage de Perl one-liners nécessite un travail mental pour moi, donc je préfère retirer autant de personnages que possible. L'habitude était nuisible dans ce cas.
jfs
2
L'une des rares solutions qui ne charge pas tout dans la RAM.
Erik Aronesty
28

Mes quinze cents:

$ cat file.txt | xargs  | sed -e 's/\ /+/g' | bc

Exemple:

$ cat text
1
2
3
3
4
5
6
78
9
0
1
2
3
4
576
7
4444
$ cat text | xargs  | sed -e 's/\ /+/g' | bc 
5148
monde innocent
la source
Mon entrée peut contenir des lignes vides, j'ai donc utilisé ce que vous avez publié ici plus un grep -v '^$'. Merci!
James Oravec
sensationnel!! votre réponse est incroyable! mon préféré de tous dans la foulée
thahgr
J'adore cela et +1 pour le pipeline. Solution très simple et facile pour moi
Gelin Luo
24

J'ai fait une référence rapide sur les réponses existantes qui

  • utilisez uniquement des outils standard (désolé pour des trucs comme luaou rocket),
  • sont de vrais one-liners,
  • sont capables d'ajouter d'énormes quantités de chiffres (100 millions), et
  • sont rapides (j'ai ignoré ceux qui ont pris plus d'une minute).

J'ai toujours ajouté les nombres de 1 à 100 millions qui étaient réalisables sur ma machine en moins d'une minute pour plusieurs solutions.

Voici les résultats:

Python

:; seq 100000000 | python -c 'import sys; print sum(map(int, sys.stdin))'
5000000050000000
# 30s
:; seq 100000000 | python -c 'import sys; print sum(int(s) for s in sys.stdin)'
5000000050000000
# 38s
:; seq 100000000 | python3 -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 27s
:; seq 100000000 | python3 -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 22s
:; seq 100000000 | pypy -c 'import sys; print(sum(map(int, sys.stdin)))'
5000000050000000
# 11s
:; seq 100000000 | pypy -c 'import sys; print(sum(int(s) for s in sys.stdin))'
5000000050000000
# 11s

Awk

:; seq 100000000 | awk '{s+=$1} END {print s}'
5000000050000000
# 22s

Coller & Bc

Cela a manqué de mémoire sur ma machine. Cela a fonctionné pour la moitié de la taille de l'entrée (50 millions de numéros):

:; seq 50000000 | paste -s -d+ - | bc
1250000025000000
# 17s
:; seq 50000001 100000000 | paste -s -d+ - | bc
3750000025000000
# 18s

Je suppose donc qu'il aurait fallu environ 35 secondes pour les 100 millions de numéros.

Perl

:; seq 100000000 | perl -lne '$x += $_; END { print $x; }'
5000000050000000
# 15s
:; seq 100000000 | perl -e 'map {$x += $_} <> and print $x'
5000000050000000
# 48s

Rubis

:; seq 100000000 | ruby -e "puts ARGF.map(&:to_i).inject(&:+)"
5000000050000000
# 30s

C

À titre de comparaison, j'ai compilé la version C et je l'ai également testée, juste pour avoir une idée de la lenteur des solutions basées sur les outils.

#include <stdio.h>
int main(int argc, char** argv) {
    long sum = 0;
    long i = 0;
    while(scanf("%ld", &i) == 1) {
        sum = sum + i;
    }
    printf("%ld\n", sum);
    return 0;
}

 

:; seq 100000000 | ./a.out 
5000000050000000
# 8s

Conclusion

C est bien sûr le plus rapide avec 8 s, mais la solution Pypy n'ajoute qu'un très petit surcoût d'environ 30% à 11 s . Mais, pour être juste, Pypy n'est pas exactement standard. La plupart des gens n'ont installé que CPython, ce qui est beaucoup plus lent (22 s), exactement aussi vite que la solution Awk populaire.

La solution la plus rapide basée sur des outils standard est Perl (15s).

Alfe
la source
2
L' approche paste+ bcétait exactement ce que je cherchais pour additionner les valeurs hexadécimales, merci!
Tomislav Nakic-Alfirevic
1
Juste pour le plaisir, à Rust:use std::io::{self, BufRead}; fn main() { let stdin = io::stdin(); let mut sum: i64 = 0; for line in stdin.lock().lines() { sum += line.unwrap().parse::<i64>().unwrap(); } println!("{}", sum); }
Jocelyn
réponse géniale. ne pas tergiverser mais il est vrai que si vous décidiez d'inclure ces résultats plus longs, la réponse serait encore plus impressionnante!
Steven Lu
@StevenLu J'ai senti que la réponse serait juste plus longue et donc moins impressionnante (pour reprendre vos mots). Mais je peux comprendre que ce sentiment ne doit pas être partagé par tout le monde :)
Alfe
Suivant: numba + parallélisation
gerrit
17

Doublure simple bash one

$ cat > /tmp/test
1 
2 
3 
4 
5
^D

$ echo $(( $(cat /tmp/test | tr "\n" "+" ) 0 ))
Khaja Minhajuddin
la source
7
Aucun chat nécessaire: echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
agc
2
trn'est pas exactement "plain Bash" / nitpick
Benjamin W.
17

Solution BASH, si vous voulez en faire une commande (par exemple si vous devez le faire fréquemment):

addnums () {
  local total=0
  while read val; do
    (( total += val ))
  done
  echo $total
}

Puis utilisation:

addnums < /tmp/nums
Jay
la source
14

Je pense que AWK est ce que vous recherchez:

awk '{sum+=$1}END{print sum}'

Vous pouvez utiliser cette commande soit en passant la liste des nombres via l'entrée standard, soit en passant le fichier contenant les nombres en tant que paramètre.

Paolo
la source
11

Les travaux suivants dans bash:

I=0

for N in `cat numbers.txt`
do
    I=`expr $I + $N`
done

echo $I
Francisco Canedo
la source
1
L'extension de commande doit être utilisée avec prudence lorsque les fichiers peuvent être arbitrairement volumineux. Avec nombres.txt de 10 Mo, l' cat numbers.txtétape serait problématique.
Giacomo
1
En effet, cependant (sinon pour les meilleures solutions trouvées ici), j'utiliserais celui-ci jusqu'à ce que je rencontre réellement ce problème.
Francisco Canedo
11

Vous pouvez utiliser num-utils, même si cela peut être exagéré pour ce dont vous avez besoin. Il s'agit d'un ensemble de programmes pour manipuler les nombres dans le shell, et peut faire plusieurs choses astucieuses, y compris bien sûr, les additionner. C'est un peu dépassé, mais ils fonctionnent toujours et peuvent être utiles si vous avez besoin de faire quelque chose de plus.

http://suso.suso.org/programs/num-utils/

sykora
la source
Exemple: numsum numbers.txt.
agc
9

Je me rends compte que c'est une vieille question, mais j'aime assez cette solution pour la partager.

% cat > numbers.txt
1 
2 
3 
4 
5
^D
% cat numbers.txt | perl -lpe '$c+=$_}{$_=$c'
15

S'il y a un intérêt, je vais vous expliquer comment cela fonctionne.

Nym
la source
10
S'il vous plait, ne le faites pas. Nous aimons prétendre que -n et -p sont de belles choses sémantiques, pas seulement un collage de cordes intelligent;)
hobbs
2
Oui s'il vous plaît, expliquez :) (Je ne suis pas un gars de type Perl.)
Jens
1
Essayez d'exécuter "perl -MO = Deparse -lpe '$ c + = $ _} {$ _ = $ c'" et en regardant la sortie, -l utilise essentiellement des sauts de ligne et des séparateurs d'entrée et de sortie, et -p imprime chaque ligne. Mais pour faire '-p', perl ajoute d'abord une plaque de chaudière (que -MO = Deparse) vous montrera, mais ensuite il ne fait que remplacer et compiler. Vous pouvez donc provoquer l'insertion d'un bloc supplémentaire avec la partie '} {' et l'inciter à ne pas imprimer sur chaque ligne, mais à imprimer à la toute fin.
Nym
9

Pure bash et dans une doublure :-)

$ cat numbers.txt
1
2
3
4
5
6
7
8
9
10


$ I=0; for N in $(cat numbers.txt); do I=$(($I + $N)); done; echo $I
55
Oliver Ertl
la source
Pourquoi y a-t-il deux ((parenthèses ))?
Atcold
Pas vraiment un coup bas à cause du chat. faites-le pur bash en remplaçant cat par$(< numbers.txt)
Dani_l
9
sed 's/^/.+/' infile | bc | tail -1
Dominique
la source
6

Alternative pure Perl, assez lisible, aucun package ni option requis:

perl -e "map {$x += $_} <> and print $x" < infile.txt
clint
la source
ou un tout petit peu plus court: perl -e 'map {$ x + = $ _} <>; print $ x 'infile.txt
Avi Tevet
La mémoire requise est de près de 2 Go pour une grande entrée de 10 millions de numéros
Amit Naidu
6

Pour les amateurs de rubis

ruby -e "puts ARGF.map(&:to_i).inject(&:+)" numbers.txt
johnlinvc
la source
5

Impossible d'éviter de soumettre ceci:

jot 1000000 | sed '2,$s/$/+/;$s/$/p/' | dc

On le trouve ici: Le
plus élégant one-liner shell unix pour résumer la liste des nombres de précision arbitraire?

Et voici ses avantages spéciaux par rapport à awk, bc et ses amis:

  • cela ne dépend pas de la mise en mémoire tampon et ne s'étouffe donc pas avec de très grandes entrées
  • cela n'implique aucune précision particulière - ou taille entière pour cette matière - limite
  • pas besoin de code différent, si des nombres à virgule flottante doivent être ajoutés
fgeorgatos
la source
Veuillez inclure le code lié à la question dans la réponse et ne pas faire référence à un lien
Ibo
5

Utilisation de l' utilitaire GNU datamash :

seq 10 | datamash sum 1

Production:

55

Si les données d'entrée sont irrégulières, avec des espaces et des tabulations à des endroits impairs, cela peut être source de confusion datamash, alors utilisez le -Wcommutateur:

<commands...> | datamash -W sum 1

... ou utilisez trpour nettoyer l'espace blanc:

<commands...> | tr -d '[[:blank:]]' | datamash sum 1
agc
la source
4

Ma version:

seq -5 10 | xargs printf "- - %s" | xargs  | bc
Vytenis Bivainis
la source
2
Plus court:seq -s+ -5 10 | bc
agc
3

Vous pouvez le faire en python, si vous vous sentez à l'aise:

Non testé, juste tapé:

out = open("filename").read();
lines = out.split('\n')
ints = map(int, lines)
s = sum(ints)
print s

Sebastian a souligné un script à une ligne:

cat filename | python -c"from fileinput import input; print sum(map(int, input()))"
Tiago
la source
python -c "à partir de l'entrée d'importation de fileinput; print sum (map (int, input ()))"
numbers.txt
2
cat is overused, redirect stdin from file: python -c "..." <numbers.txt
Giacomo
2
@rjack: catest utilisé pour démontrer que le script fonctionne à la fois pour stdin et pour les fichiers dans argv [] (comme while(<>)dans Perl). Si votre entrée se trouve dans un fichier, «<» n'est pas nécessaire.
jfs
2
Mais < numbers.txtdémontre que cela fonctionne aussi bien sur stdin cat numbers.txt |. Et cela n'enseigne pas les mauvaises habitudes.
Xiong Chiamiov
3
$ cat n
2
4
2
7
8
9
$ perl -MList::Util -le 'print List::Util::sum(<>)' < n
32

Ou, vous pouvez taper les chiffres sur la ligne de commande:

$ perl -MList::Util -le 'print List::Util::sum(<>)'
1
3
5
^D
9

Cependant, celui-ci ralentit le fichier, il n'est donc pas judicieux de l'utiliser sur des fichiers volumineux. Voir la réponse de j_random_hacker qui évite le slurping.

Sinan Ünür
la source
3

Les éléments suivants devraient fonctionner (en supposant que votre numéro est le deuxième champ de chaque ligne).

awk 'BEGIN {sum=0} \
 {sum=sum + $2} \
END {print "tot:", sum}' Yourinputfile.txt
James Anderson
la source
2
Vous n'avez pas vraiment besoin de la partie {sum = 0}
Uphill_ What '1
3

Une doublure en raquette:

racket -e '(define (g) (define i (read)) (if (eof-object? i) empty (cons i (g)))) (foldr + 0 (g))' < numlist.txt
b2coutts
la source
3

C (non simplifié)

seq 1 10 | tcc -run <(cat << EOF
#include <stdio.h>
int main(int argc, char** argv) {
    int sum = 0;
    int i = 0;
    while(scanf("%d", &i) == 1) {
        sum = sum + i;
    }
    printf("%d\n", sum);
    return 0;
}
EOF)
Greg Bowyer
la source
J'ai dû voter positivement. Il n'y a rien de mal à la réponse - c'est assez bon. Cependant, pour montrer que le commentaire rend la réponse impressionnante, je vote simplement le commentaire.
bballdave025
3

Toutes mes excuses à l'avance pour la lisibilité des backticks (""), mais ceux-ci fonctionnent dans des shells autres que bash et sont donc plus collables. Si vous utilisez un shell qui l'accepte, le format $ (command ...) est beaucoup plus lisible (et donc déboguable) que `command ...` alors n'hésitez pas à le modifier pour votre raison.

J'ai une fonction simple dans mon bashrc qui utilisera awk pour calculer un certain nombre d'éléments mathématiques simples

calc(){
  awk 'BEGIN{print '"$@"' }'
}

Cela fera +, -, *, /, ^,%, sqrt, sin, cos, parenthesis .... (et plus en fonction de votre version de awk) ... vous pourriez même avoir de l'imagination avec printf et le format à virgule flottante sortie, mais c'est tout ce dont j'ai normalement besoin

pour cette question particulière, je ferais simplement ceci pour chaque ligne:

calc `echo "$@"|tr " " "+"`

donc le bloc de code pour additionner chaque ligne ressemblerait à ceci:

while read LINE || [ "$LINE" ]; do
  calc `echo "$LINE"|tr " " "+"` #you may want to filter out some lines with a case statement here
done

C'est si vous vouliez seulement les additionner ligne par ligne. Cependant, pour un total de chaque nombre dans le fichier de données

VARS=`<datafile`
calc `echo ${VARS// /+}`

btw si j'ai besoin de faire quelque chose de rapide sur le bureau, j'utilise ceci:

xcalc() { 
  A=`calc "$@"`
  A=`Xdialog --stdout --inputbox "Simple calculator" 0 0 $A`
  [ $A ] && xcalc $A
}
technosaurus
la source
2
Quel type de coquille ancienne utilisez-vous qui ne prend pas en charge $()?
nyuszika7h