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 sed
reformatage, 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é expr
dans 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?
Réponses:
Un peu d'awk devrait le faire?
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
printf
plutôt queprint
:la source
ls $@ | xargs -i pdftk {} dump_data | grep NumberOfPages | awk '{s+=$2} END {print s}'
awk '{s+=$1} END {printf "%.0f", s}' mydatafile
plutôt.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.
Alternativement, lorsque vous canalisez depuis stdin,
la source
paste
pouvez 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
-
. (C'est utile si vous souhaitez combiner un fichier avec stdin).La version monoligne en Python:
la source
python -c"import sys; print(sum(map(int, sys.stdin)))"
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))"
import sys; print(sum(int(''.join(c for c in l if c.isdigit())) for l in sys.stdin))
Je mettrais un gros AVERTISSEMENT sur la solution couramment approuvée:
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:
la source
echo -e "2147483647 \n 100" |awk '{s+=$1}END{print s}'
montre2147483747
echo 999999999999999999 | awk '{s+=$1} END {printf "%.0f\n", s}'
produit1000000000000000000
Bash simple:
la source
num
défini? Je crois en quelque sorte que cela est lié à l'< numbers.txt
expression, mais on ne sait pas comment.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, viatr '-' '_' | 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 :Comme pseudo-code:
Pour vraiment comprendre la simplicité et la puissance de
dc
, voici un script Python fonctionnel qui implémente certaines des commandes dedc
et exécute une version Python de la commande ci-dessus:la source
(echo "0"; sed 's/$/ +/' inp; echo 'pq')|dc
.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.sed
substitution peut être supprimé, car peu importe lesdc
espaces entre les arguments et les opérateurs.(echo "0"; sed 's/$/+/' inputFile; echo 'pq')|dc
Avec jq :
la source
Bash pur et court.
la source
f=$(<numbers.txt)
.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).<numbers.txt
est 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, laawk
solution 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.la source
Mes quinze cents:
Exemple:
la source
grep -v '^$'
. Merci!J'ai fait une référence rapide sur les réponses existantes qui
lua
ourocket
),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
Awk
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):
Je suppose donc qu'il aurait fallu environ 35 secondes pour les 100 millions de numéros.
Perl
Rubis
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.
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).
la source
paste
+bc
était exactement ce que je cherchais pour additionner les valeurs hexadécimales, merci!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); }
Doublure simple bash one
la source
echo $(( $( tr "\n" "+" < /tmp/test) 0 ))
tr
n'est pas exactement "plain Bash" / nitpickSolution BASH, si vous voulez en faire une commande (par exemple si vous devez le faire fréquemment):
Puis utilisation:
la source
Je pense que AWK est ce que vous recherchez:
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.
la source
Les travaux suivants dans bash:
la source
cat numbers.txt
étape serait problématique.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/
la source
numsum numbers.txt
.Je me rends compte que c'est une vieille question, mais j'aime assez cette solution pour la partager.
S'il y a un intérêt, je vais vous expliquer comment cela fonctionne.
la source
Pure bash et dans une doublure :-)
la source
((
parenthèses))
?$(< numbers.txt)
la source
Alternative pure Perl, assez lisible, aucun package ni option requis:
la source
Pour les amateurs de rubis
la source
Impossible d'éviter de soumettre ceci:
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:
la source
Utilisation de l' utilitaire GNU
datamash
:Production:
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-W
commutateur:... ou utilisez
tr
pour nettoyer l'espace blanc:la source
Ma version:
la source
seq -s+ -5 10 | bc
Vous pouvez le faire en python, si vous vous sentez à l'aise:
Non testé, juste tapé:
Sebastian a souligné un script à une ligne:
la source
cat
est utilisé pour démontrer que le script fonctionne à la fois pour stdin et pour les fichiers dans argv [] (commewhile(<>)
dans Perl). Si votre entrée se trouve dans un fichier, «<» n'est pas nécessaire.< numbers.txt
démontre que cela fonctionne aussi bien sur stdincat numbers.txt |
. Et cela n'enseigne pas les mauvaises habitudes.Ou, vous pouvez taper les chiffres sur la ligne de commande:
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.
la source
Les éléments suivants devraient fonctionner (en supposant que votre numéro est le deuxième champ de chaque ligne).
la source
Une doublure en raquette:
la source
C (non simplifié)
la source
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
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:
donc le bloc de code pour additionner chaque ligne ressemblerait à ceci:
C'est si vous vouliez seulement les additionner ligne par ligne. Cependant, pour un total de chaque nombre dans le fichier de données
btw si j'ai besoin de faire quelque chose de rapide sur le bureau, j'utilise ceci:
la source
$()
?