LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Make a countdown column with awk (https://www.linuxquestions.org/questions/linux-newbie-8/make-a-countdown-column-with-awk-4175679015/)

Drosera_capensis 07-19-2020 06:03 PM

Make a countdown column with awk
 
Hello everyone,

A little question about awk.
Given a column of numbers in a "list" file.
0
1
2
3
4
5

I wish to print a list displaying (sum - value) at each row, as a countdown of the sum of the first list.
15
13
10
6
1
0

I have tried to set up a script to do it, but it does not work.

Code:

cat list |  awk ' BEGIN {S+=$1} END {a=$1} {print (S-$a)}'
Would anyone has a solution for this?

syg00 07-19-2020 06:47 PM

BEGIN block is only entered once - likewise the END block; one right at the start, one right at the finish. You don't need the BEGIN. There are other logic errors, but that is for you to solve.

berndbausch 07-19-2020 06:49 PM

The action at the END is meaningless, since there is no $1 at the END and you do nothing with variable "a".
Similarly, there is no $1 at the BEGINning.
The print action is executed at each input line, but there is no such thing as $a in awk. I suppose you get syntax errors and the program doesn't even start running.

Now, I don't really understand how to correlate the input and output, otherwise I could give you hints how to construct the awk program. 15 is obviously the sum of all numbers, but how do you compute 13? I would have expected 14 there (sum is 15, value is 1, sum-value is 14).

EDIT: In any case, you need two passes over the file, since you need to know the sum of all numbers when processing the first line.

berndbausch 07-19-2020 06:51 PM

Oh, and you commit cat abuse, too.

scasey 07-19-2020 07:06 PM

Quote:

Originally Posted by berndbausch (Post 6147132)
Now, I don't really understand how to correlate the input and output, otherwise I could give you hints how to construct the awk program. 15 is obviously the sum of all numbers, but how do you compute 13? I would have expected 14 there (sum is 15, value is 1, sum-value is 14).

I don’t understand either...looks to me like the result needs to be:
15
10
6
3
1
0
Pseudo code:
Get the sum of all lines...print it
Read through the list in reverse order
Subtract the amount on each line from the total and print the result.

Homework??

Drosera_capensis 07-20-2020 03:43 AM

Thank you for your comments.
There is indeed a mistake in my example.
The input:
0
1
2
3
4
5

The output:
15
14
12
9
5
0

It makes more sense now!
syg00 here is my explanation of the use of BEGIN and END.

For the formula:
I produce a sum of the columns with {S+=$1}. I add BEGIN for this operation would be done before the others.
I then record the value of column 1 in the variable a. It is quoted $a afterward to indicate it is a variable.
Finally, I print the subtraction sum_of_the_column - $a. I have added END for these operations to be done after the sum.

scasey what you describe is exactly why I have tried to do.
I am aware that if no one recognize the formula it is very far from the solution.
I will search for another way to design this script.

pan64 07-20-2020 04:01 AM

Quote:

Originally Posted by Drosera_capensis (Post 6147189)
I don't know what to do, I have been working with awk for one year now, and I am still as bad as when I started.

You need to understand how awk works.
awk is something like a for loop (like sed/grep and other "similar" apps). I mean they take one line at once, and process the input line by line.
So the awk (grep/sed/...) script will be executed on every and each line.
BEGIN and END are two keywords. BEGIN and END blocks will be executed only once, before the first line an after the last. (ok, there is an exception where we have more than one input files, but you can ignore it right now).

From the other hand the 15 is the total sum of those numbers, you need to process all the lines to get it.
To get the result list you need to process all the lines once more.

This is the second half:
Code:

awk -vX=15 '{X-=$1; print X}' a.list

shruggy 07-20-2020 04:18 AM

Quote:

Originally Posted by pan64 (Post 6147191)
To get the result list you need to process all the lines once more.

@OP. And Turbocapitalist once already explained to you how to do this.

Drosera_capensis 07-20-2020 04:41 AM

Much thanks to your answer pan64.
Here is a script that I have set up based on yours.
I was unaware that variables ($a here) were not usable in the awk command, and that -v was used to input variables.
That was what berndbausch was referring to with $a, without quoting it literally.

Quote:

a=$(awk ' {sum=sum+$1}END{print sum}' list)
awk -vX=$a '{X-=$1; print X}' list
Thank you shruggy, I have forgotten this post which is less than three months old. It is indeed the exact same problem.
I tend to forget a lot.
I will find tutorials and will try to train on awk daily, else I will forget again.
Thanks for your help.

pan64 07-20-2020 04:44 AM

glad to help you.
If you really want to say thanks just click on yes.

grail 07-20-2020 06:07 AM

Now that you seem to have a process that works for you.

May I suggest you look at your awk manual you are using, or this one if you do not,
and try placing the numbers in an array whilst summing your total and then you can simply use your END block to unpack the array in the order you like and subtract at will

allend 07-20-2020 09:17 AM

To achieve the required output, it is easier to store the running totals (from s+=$1) into an array (with t[NR]=s), then use the END block to subtract each running total from the final sum (with {(for i in t) {print s-t[i]}} ).

shruggy 07-20-2020 09:29 AM

@allend. Even saving the running totals is not needed. I believe what grail implied above was
Code:

awk '{s+=$1;_[$1]}END{for(i in _)print i,s-i}'

MadeInGermany 07-20-2020 09:46 AM

You can let awk read the input twice. At the first pass (where NR equals FNR) sum up and jump to the next input cycle (skipping the following code).
At the second pass run the following code.
Code:

awk 'NR==FNR { X+=$1; next } { X-=$1; print X }' list list


All times are GMT -5. The time now is 09:53 PM.