Чтение, хранение и доступ к временным файлам (BASH)

Я хочу загрузить временные файлы с кучей чисел из входного файла. Формат этого скрипта: "testing -row/-col [входной файл]". Входной файл в основном просто набор случайных чисел, таких как

1 2 3 4
3 3 5 6
9 4 4 2

Мой код ниже пытается получить этот входной файл в качестве аргумента, а затем "кошачьи" эти числа в новые временные файлы. Оттуда я пытаюсь найти среднее значение строки из этих временных файлов.

FILENAME=$2
TMP=./TMP2.$$
cat $FILENAME > $TMP

#average row 
function avg_row {
while read -a row  
do
    total=0
    sum=0
    for i in "${rows[@]}"
    do
         eum=`expr $sum + $i`
         total=`expr $total + 1`
    done
    average=`expr $sum / $total`
    echo $average
done < $TMP
}

Тем не менее, даже если я "перехватываю" файлы TMP, они отображаются точно так же, как и test_file, когда я запускаю скрипт, он печатает

 expr: division by zero
 expr: division by zero
 expr: division by zero

Любые предложения или идеи о том, почему это может произойти? Спасибо.

1 ответ

Решение

Два вопроса:

  1. Ваша функция читает в массиве row но затем пытается получить доступ к несуществующему массиву rows, Так как rows не имеет записей, total никогда не увеличивается, и деление делится на ноль.

  2. Эта линия обновлений eumне sum:

    eum=`expr $sum + $i`
    

Кроме того, неясно, почему содержимое $FILENAME копируется перед прочтением. Я предполагаю, что у вас есть веская причина для этого.

Исправленная функция выглядит так:

function avg_row {
while read -a row  
do
    total=0
    sum=0
    for i in "${row[@]}"
    do
         sum=`expr $sum + $i`
         total=`expr $total + 1`
    done
    average=`expr $sum / $total`
    echo $average
done < $TMP

Это производит вывод:

$ avg_row
2
4
4

Модернизированная версия Bash

Оба клюшки и expr архаичны Более современная версия функции bash:

avg_row2() {
while read -a row
do
    sum=0
    for i in "${row[@]}"
    do
        ((sum += i))
    done
    echo $((sum / ${#row[@]}))
done < $TMP
}

Это дает тот же результат, что и раньше:

$ avg_row2
2
4
4

версия awk

То же самое можно сделать в awk:

$ awk '{s=0; for (i=1;i<=NF;i++) s+=$i; print int(s/NF);}' filename
2
4
4

В отличие от bash, awk может выполнять арифметику с плавающей запятой:

$ awk '{s=0; for (i=1;i<=NF;i++) s+=$i; print s/NF;}' filename
2.5
4.25
4.75
Другие вопросы по тегам