Сценарий оболочки для суммирования столбцов, связанных с именем

#bash #shell #sum #ksh

#bash #оболочка #сумма #ksh

Вопрос:

У меня есть файл с тысячами чисел в столбце 1, и каждая последовательность этих чисел связана с одним человеком. Есть ли у кого-нибудь идеи о том, как я могу создать сценарий оболочки для суммирования столбца 1 для этого конкретного человека, например:

 John is 10 20 30 50 = 110
 

Вывод сценария будет следующим: John 110 и так далее и тому подобное..

Я пробовал использовать while, for и т. Д., Но я не могу связать сумму с человеком: (

Пример файла:

 10 John
20 John
30 John
50 John
10 Paul
10 Paul
20 Paul
20 Paul
20 Robert
30 Robert
30 Robert 
60 Robert 
80 Robert
40 Robert
40 Robert
40 Robert
15 Mike
30 Mike
 

Комментарии:

1. пожалуйста, обновите вопрос, указав ваши дополнительные требования (например, среднее значение) и ожидаемый результат

Ответ №1:

Одно awk решение, которое выводит средние значения с точностью до 2 знаков после запятой и упорядочивает вывод по имени:

 awk '
    { total[$2] =$1
      count[$2]  
    }
END { PROCINFO["sorted_in"]="@ind_str_asc"
      for ( i in total )
          printf "%-10s ] / %-5d = %5.2fn", i, total[i], count[i], total[i]/count[i]
    }
' numbers.dat
 

Это генерирует:

 John         110 / 4     = 27.50
Mike          45 / 2     = 22.50
Paul          60 / 4     = 15.00
Robert       340 / 8     = 42.50
 

Ответ №2:

 awk '{ map[$2] =$1 } END { for (i in map) { print i" "map[i] } }' file
 

Используя awk, создайте массив с именем в качестве первого индекса и текущим итогом значений для каждого имени. В конце выведите имена и итоговые значения.

Ответ №3:

Большое спасибо Раману, это сработало… вы случайно не знаете, возможно ли выполнить вычисление для одного и того же awk, чтобы получить среднее значение для каждого из них? Например, Джон 10 20 30 50 = 110, 110 / 4 = 27

Ответ №4:

Предположения:

  • данные хранятся в файле с именем numbers.dat
  • мы будем хранить итоговые значения и подсчеты в массивах, но вычислять средние значения просто для отображения (OP может решить, следует ли также сохранять средние значения в массиве)

Одно bash из решений, использующее пару ассоциативных массивов для отслеживания наших чисел:

 unset      total count
declare -A total count

while read -r number name
do
    (( total[${name}]  = $number))
    (( count[${name}]    ))
done < numbers.dat

typeset -p total count
 

Это генерирует:

 declare -A total=([Mike]="45" [Robert]="340" [John]="110" [Paul]="60" )
declare -A count=([Mike]="2" [Robert]="8" [John]="4" [Paul]="4" )
 

Если нам нужны средние значения на основе целых чисел (т. Е. Без десятичных знаков):

 for i in ${!total[@]}
do
   printf "%-10s ] / %-5d = ]n" "${i}" "${total[${i}]}" "${count[${i}]}" $(( ${total[${i}]} / ${count[${i}]} ))
done
 

Это генерирует:

 Mike          45 / 2     =    22
Robert       340 / 8     =    42
John         110 / 4     =    27
Paul          60 / 4     =    15
 

Если мы хотим, чтобы средние значения включали, скажем, 2 знака после запятой:

 for i in ${!total[@]}
do
   printf "%-10s ] / %-5d = %5.2fn" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done
 

Это генерирует:

 Mike          45 / 2     = 22.50
Robert       340 / 8     = 42.50
John         110 / 4     = 27.50
Paul          60 / 4     = 15.00
 

Выходные данные отсортированы по имени:

 for i in ${!total[@]}
do
   printf "%-10s ] / %-5d = %5.2fn" "${i}" "${total[${i}]}" "${count[${i}]}" $( bc <<< "scale=2;${total[${i}]} / ${count[${i}]}" )
done | sort
 

Это генерирует:

 John         110 / 4     = 27.50
Mike          45 / 2     = 22.50
Paul          60 / 4     = 15.00
Robert       340 / 8     = 42.50