Cada linha contém texto e números em uma coluna. Eu preciso calcular a soma dos números em cada linha. Como eu posso fazer isso? Valeu
example.log contém:
time=31sec
time=192sec
time=18sec
time=543sec
A resposta deve ser 784
Cada linha contém texto e números em uma coluna. Eu preciso calcular a soma dos números em cada linha. Como eu posso fazer isso? Valeu
example.log contém:
time=31sec
time=192sec
time=18sec
time=543sec
A resposta deve ser 784
Respostas:
Com uma versão mais recente (4.x) do GNU awk
:
awk 'BEGIN {FPAT="[0-9]+"}{s+=$1}END{print s}'
Com outras awk
tentativas:
awk -F '[a-z=]*' '{s+=$2}END{print s}'
s+0
, caso s
esteja vazio, ele será impresso em 0
vez de vazio.
s
pode estar vazio; se os dados de entrada não contiverem linhas (ou seja, se não houver nenhuma entrada ). Nesse caso, existem dois comportamentos possíveis; 1) sem entrada => sem saída, ou 2) sempre produz algo, se apenas 0. Ambos são opções sensíveis, dependendo do contexto da aplicação. A +0
opção de endereçamento 2). Para abordar a opção 1), você prefere escrever END {if(s) print s}
. - Portanto, não faz sentido assumir uma das opções (neste caso de canto sem dados) até que seja especificada pela pergunta.
awk -F= '{sum+=$2};END{print sum}'
time=1.4e5sec
Outro GNU awk
:
awk -v RS='[0-9]+' '{n+=RT};END{print n}'
Um perl
:
perl -lne'$n+=$_ for/\d+/g}{print$n'
POSIX:
tr -cs 0-9 '[\n*]' | grep . | paste -sd + - | bc
sed 's/=/ /' file | awk '{ sum+=$2 } END { print sum}'
sed
:awk --field-separator = '{ sum+=$2 } END { print sum}' data.dat
-F'='
vez de #--field-separator =
man awk
único dá -F fs
e--field-separator fs
-F'='
ou -F '='
existem duas maneiras de fazer isso -F fs
(fs é "=" no seu caso). Eu adicionei os singlequotes para garantir que os fs está devidamente visto e interpretado por awk, não o shell (útil se os fs é ';', por exemplo)
Todo mundo postou awk
respostas incríveis , das quais eu gosto muito.
Uma variação para @cuonglm substituindo grep
por sed
:
sed 's/[^0-9]//g' example.log | paste -sd'+' - | bc
sed
tiras tudo, exceto para os números.paste -sd+ -
comando une todas as linhas como uma única linhabc
avalia a expressãoVocê deve usar uma calculadora.
{ tr = \ | xargs printf '[%s=]P%d+p' | dc; } <infile 2>/dev/null
Com suas quatro linhas que imprimem:
time=31
time=223
time=241
time=784
E mais simplesmente:
tr times=c ' + p' <infile |dc
... que imprime ...
31
223
241
784
Se a velocidade é o que você procura, dc
é o que deseja. Tradicionalmente, era bc
o compilador - e ainda é para muitos sistemas.
dc
mais próximo que eu posso dizer. Do que você está falando?
perl
do conjunto de ferramentas padrão do unix - realmente não faz muito sentido se você usar as ferramentas GNU compiladas em uma cadeia de ferramentas GNU. Todo o inchaço que pode afetar negativamente o desempenho do Perl também está em todos os utilitários GNU compilados pelo GNU. Triste mas verdadeiro. Você precisa de um conjunto de ferramentas simples, simples e simples, para avaliar com precisão a diferença. Como um conjunto de ferramentas de herança ligado estaticamente a bibliotecas muçulmanas, por exemplo - dessa maneira, você pode comparar o paradigma de uma ferramenta / uma tarefa versus o de uma ferramenta para governar todos eles.
Através do python3,
import re
with open(file) as f:
m = f.read()
l = re.findall(r'\d+', m)
print(sum(map(int, l)))
re.findall
retorna uma lista de strings, isso não vai funcionar
sum(int(e) for e in l)
seja mais pitônico.
Solução de bash pura (Bash 3+):
while IFS= read -r line; do # While it reads a line:
if [[ "$line" =~ [0-9]+ ]]; then # If the line contains numbers:
((counter+=BASH_REMATCH[0])) # Add the current number to counter
fi # End if.
done # End loop.
echo "Total number: $counter" # Print the number.
unset counter # Reset counter to 0.
Versão curta:
while IFS= read -r l; do [[ "$l" =~ [0-9]+ ]] && ((c+=BASH_REMATCH)); done; echo $c; c=0
PS4='$((x+=${time%s*}))' time=0 x=0 sh -x <infile