Bash: невозможно вычислить сумму списка целых чисел в bash; - PullRequest
0 голосов
/ 17 марта 2020

У меня проблема с вычислением в оболочке bash общей суммы целых чисел, полученных из файла. Целые числа, которые я хочу суммировать, находятся в последнем поле с awk ($ NF) каждой строки.

Технически, вот мои bash команды:

sum=0
for i in $(grep 'number_vars' file.txt | sed 's/_//g;s/,/./g;s/\.00//g' | awk '{print $NF}'); do sum=$((sum+i)); done

К сожалению, Эта последняя команда выдает ошибку: syntax error: invalid arithmetic operator, и я не понимаю, почему.

Итак, я продолжал пытаться исправить эту ошибку, сохраняя все целые числа в файле temp.dat как:

for i in $(grep 'numbers_vars' file.txt | sed 's/_//g;s/,/./g;s/\.00//g' | awk '{print $NF}'); do echo $i >> temp.dat; done

Я получаю следующее содержание для temp.dat:

$ cat temp.dat 
    500
    110
    300
    110
    110
    110
    1500
    110
    1500
    110
    110
    110
    3000
    110
    110
    110
    3000
    3000
    110
    110

Тогда, если я это сделаю:

sum=0
for i in $(cat temp.dat); do sum=$((sum+i)); done

,

всегда одинаковые ошибка: syntax error: invalid arithmetic operator

Я также пытался: sum=$(($sum+$i)), но безуспешно.

Я не знаю, что теперь делать.

ОБНОВЛЕНИЕ 1: УИЛСОН соответствует фамилии:

$ LC_ALL=C cat -vt file_in.txt | grep WILSON 

WILSON PETER "^I^I500,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER "^I^I300,00^M
MR WILSON CHRISTOPHE VIREMENT S ^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
MR WILSON CHRISTOPHE VIREMENT S ^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER "^I^I1_500,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER "^I^I1_500,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER MR WILSON J MR WILSON PETER "^I^I110,00^M
WILSON PETER "^I^I3_000,00^M
...

ОБНОВЛЕНИЕ 2: РЕШЕНИЕ Я узнал, как получить хороший отформатированный текст файл (.txt), т.е. файл, в котором каждая строка соответствует строке исходной таблицы Excel. Я должен сделать вывод, что инструмент экспорта Excel 2019 на моей MacOS Catalina действительно чушь собачья: я понял, редактируя сгенерированный текстовый файл, все смешалось, то есть строка может быть частью всей строки таблицы Excel и т. Д. c .. Наконец, я ничего не мог сделать с этим плохим форматированием.

РЕШЕНИЕ: , если это может помочь кому-то, кто хочет быстро обработать таблицу Excel с функциями bash, ниже того, что я did.

1) First export the Excel table to a PDF file
2) Open PDF file with Acrobat and export it to "raw text"
3) Then, I can check with `vim` is well formatted, i.e "a line in Excel table" equal to "one line in text file
4) After this checking, you can apply the different solutions suggested by all the people who helped me to compute the sum of the desired column.
For example, by following the procedure above from 1) to 4), I have just to do : 

awk '{sum+=$2}END{print sum}' file.txt

Наконец, не забывайте, что это не проблема с моими командами терминала, которые являются правильными, а скорее о плохом текстовом файле, генерируемом Excel.

Итак, я нашел способ обойти проблему, используя посреднический инструмент (Acrobat). Я согласен, что это немного сложно, но мне не удалось добиться большего успеха с единственным инструментом экспорта текста в Excel.

Надеюсь, это будет полезно.

Спасибо

Ответы [ 4 ]

1 голос
/ 17 марта 2020

Ваша основная c проблема в том, что ваш файл имеет Windows окончания строк (CR-LF), а CR (aka \r aka control-M) выглядит как обычный символ bash. Вы можете избавиться от них так же, как и от подчеркивания, используя sed. Или вы можете использовать инструмент dos2unix или отфильтровать файл через tr -d '\r'. Кроме того, многие текстовые редакторы сделают это за вас.

Использование набора инструментов для простой модификации, подобной этой, не является самым эффективным, поскольку вы можете выполнить все преобразования и сумму в awk.

1 голос
/ 17 марта 2020

Попробуйте:

grep WILSON file_in.txt | sed 's/.*\x09//;s/\r//' | awk '{s+=$0}END{print s}'
  • s/.*\x09//; - удалить все, вплоть до \x09 символа.
  • s/\r// - удалить конец строки DOS из конец файла

будет быстрее фильтровать в awk:

sed 's/.*\x09//;s/\r//' file_in.txt | awk '/WILSON/{s+=$0}END{print s}'
1 голос
/ 17 марта 2020

из вашего temp.dat файла вы можете попробовать:

awk '{s+=$1} END {print s}' temp.dat
1 голос
/ 17 марта 2020

У меня нет видимости исходных входных данных, но вы должны быть в состоянии сделать все это в awk:

sum=$(awk '
        {
          gsub(/,+/, ".", $NF);
          gsub(/[^0-9.]+/, "", $NF);
          sum += $NF;
        } END {
          print sum;
        }
     ' file.txt)

(Вы можете свернуть пробел и развернуть его в одну строку, если Вы хотите.)

Это собирает ваши логи c полностью в awk, включая добавление, выводит только окончательную сумму.

Обратите внимание, awk может обрабатывать десятичные дроби, поэтому я оставил их неповрежденными. Оболочка POSIX и bash могут не обрабатывать десятичные дроби. Ваш s/\.00//g странный для меня, поскольку он превратит 5.004 в 54, но, возможно, у вас никогда не будет точности с точностью до сотых? И эта точность всегда .00?

AWK logi c объясняется построчно:

  • Нет условия (всегда выполняется для каждой строки):
    • Замените все последовательные запятые точкой (только в последнем поле)
    • Удалите все символы, которые не являются ни ди git, ни точкой (только в последнем поле)
      → Это решит все проблемы с невидимым символы
    • Добавить значение в переменную sum (которая автоматически инициализируется как ноль)
  • После прочтения всех строк:
    • Печать эта сумма

Если вам нужно, чтобы это окончательное значение было целым числом, скажем, потому что вы будете делать дальнейшие сравнения bash arithmeti c или Numberri c, замените эта строка print с printf "%d", sum (усечением) или printf "%.0f", sum (округлением).

Если это не решит вашу проблему, я бы хотел видеть шестнадцатеричный дамп вашего ввода с помощью hd file.txt

...