Loop over lines in file and subtract previous line from current line
Clash Royale CLAN TAG#URR8PPP
up vote
5
down vote
favorite
I have a file that contains some numbers
$ cat file.dat
0.092593
0.048631
0.027957
0.030699
0.026250
0.038156
0.011823
0.013284
0.024529
0.022498
0.013217
0.007105
0.018916
0.014079
I want to make a new file that contains the difference of the current line with the previous line. Expected output should be
$ cat newfile.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Thinking this was trivial, I started with this piece of code
f="myfile.dat"
while read line; do
curr=$line
prev=
bc <<< "$line - $prev" >> newfile.dat
done < $f
but I realized quickly that I have no idea how to access the previous line in the file. I guess I also need to account for that no subtraction should take place when reading the first line. Any guidance on how to proceed is appreciated!
bash shell-script scripting
add a comment |Â
up vote
5
down vote
favorite
I have a file that contains some numbers
$ cat file.dat
0.092593
0.048631
0.027957
0.030699
0.026250
0.038156
0.011823
0.013284
0.024529
0.022498
0.013217
0.007105
0.018916
0.014079
I want to make a new file that contains the difference of the current line with the previous line. Expected output should be
$ cat newfile.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Thinking this was trivial, I started with this piece of code
f="myfile.dat"
while read line; do
curr=$line
prev=
bc <<< "$line - $prev" >> newfile.dat
done < $f
but I realized quickly that I have no idea how to access the previous line in the file. I guess I also need to account for that no subtraction should take place when reading the first line. Any guidance on how to proceed is appreciated!
bash shell-script scripting
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
I have a file that contains some numbers
$ cat file.dat
0.092593
0.048631
0.027957
0.030699
0.026250
0.038156
0.011823
0.013284
0.024529
0.022498
0.013217
0.007105
0.018916
0.014079
I want to make a new file that contains the difference of the current line with the previous line. Expected output should be
$ cat newfile.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Thinking this was trivial, I started with this piece of code
f="myfile.dat"
while read line; do
curr=$line
prev=
bc <<< "$line - $prev" >> newfile.dat
done < $f
but I realized quickly that I have no idea how to access the previous line in the file. I guess I also need to account for that no subtraction should take place when reading the first line. Any guidance on how to proceed is appreciated!
bash shell-script scripting
I have a file that contains some numbers
$ cat file.dat
0.092593
0.048631
0.027957
0.030699
0.026250
0.038156
0.011823
0.013284
0.024529
0.022498
0.013217
0.007105
0.018916
0.014079
I want to make a new file that contains the difference of the current line with the previous line. Expected output should be
$ cat newfile.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Thinking this was trivial, I started with this piece of code
f="myfile.dat"
while read line; do
curr=$line
prev=
bc <<< "$line - $prev" >> newfile.dat
done < $f
but I realized quickly that I have no idea how to access the previous line in the file. I guess I also need to account for that no subtraction should take place when reading the first line. Any guidance on how to proceed is appreciated!
bash shell-script scripting
bash shell-script scripting
asked Sep 19 at 14:26
Yoda
16316
16316
add a comment |Â
add a comment |Â
6 Answers
6
active
oldest
votes
up vote
9
down vote
accepted
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Doing this in a shell loop calling bc
is cumbersome. The above uses a simple awk
script that reads the values off of the file one by one and for any line past the first one, it prints the difference as you describe.
The first block, NR > 1 print $0 - prev
, conditionally prints the difference between this and the previous line if we've reached line two or further (NR
is the number of records read so far, and a "record" is by default a line).
The second block, prev = $0
, unconditionally sets prev
to the value on the current line.
Redirect the output to newfile.dat
to save the result there:
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat >newfile.dat
Related:
- Why is using a shell loop to process text considered bad practice?
There was some mentioning of the slowness of calling bc
in a loop. The following is a way of using a single invocation of bc
to do the arithmetics while still reading the data in a shell loop (I would not actually recommend solving this problem in this way, and I'm only showing it here for people interested in co-processes in bash
):
#!/bin/bash
coproc bc
read prev
while read number; do
printf '%f - %fn' "$number" "$prev" >&"$COPROC[1]"
prev=$number
read -u "$COPROC[0]" result
printf '%fn' "$result"
done
<file.dat >newfile.dat
kill "$COPROC_PID"
The value in $COPROC[1]
is the standard input file descriptor of bc
while $COPROC[0]
is the standard output file descriptor of bc
.
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yodaprev
is the value on the previous line. For the first line, the first block is not executed (due to theNR > 1
condition), soprev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed beforeprev
is set to the value of the second line. The blocks are executed in order, and for each line.
â Kusalananda
Sep 19 at 14:42
@Yoda Soprev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually useprev
, it is the value of the previous line.
â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
add a comment |Â
up vote
3
down vote
Using some straightforward GNU utilities, and no shell loops:
paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc
The idea here is to duplicate the input file into two columns; offset the second column by 1 line, and paste the columns together with -
as a separator. head
and tail
are used to trim off the last line of the 1st column and first line of 2nd column respectively, to achieve the necessary offsetting. The resulting list is the required list of arithmetic differences that is piped to bc
for evaluation.
Try it online.
Alternatively, if you like sed
, you can do this:
sed '1s/$/-\/;p;d;$p;d;s/.*/&n&-\/' file.dat | bc
This duplicates each line and inserts -
at the end of the second version of each line. The first and last lines are treated differently to generate the necessary expressions. The sed output ends up something like this:
a-
b
b-
c
c-
d
These again are valid arithmetic differences that bc
can evaluate. Not that bc
understands the line-continuation backslashes at the ends of every other line.
Try it online.
add a comment |Â
up vote
2
down vote
If you wanted to try and force the shell script into working, you were just missing some initialization:
f=myfile.dat
prev=0
while read line; do
bc <<< "$line - $prev"
prev=$line
done < $f > newfile.dat
... where I also moved the redirection outside of the loop, just to save some I/O.
The bc
solution does not print leading zeroes, while the awk solution does.
1
Certainly shell loops are generally slow, but even slower is spawning abc
process for every iteration of the loop. You can simply echo the"$line - $prev"
expression into a pipe which is evaluated bybc
outside of the loop: tio.run/â¦
â Digital Trauma
Sep 19 at 17:02
add a comment |Â
up vote
2
down vote
You could use an exec
redirection to read successive lines of the input file from multiple points in the script - once before the loop (to set up the initial value), then repeatedly during it (for each new value to subtract):
exec 3<file.dat
read prev<&3
while read curr ; do
bc <<< "$curr - $prev" >> newfile.dat
prev=$curr
done <&3
1
Usingread prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.
â Kusalananda
Sep 19 at 15:00
add a comment |Â
up vote
0
down vote
I use arrays. I use them for everything. I cannot remember how awk and sed work without extensive study of the man pages. Here is the way I would do it.
f=( $(< file.dat) )
for ((num=1;num<=$#f[@];num++))
do
echo $(bc <<< $f[$num]-$f[(($num-1))])>>differences.dat
done
This is the way I understand it. It has the objectionable features of some of the other answers: looping and calling bc over and over. However, it only reads the file once, like the answers using sed and awk.
add a comment |Â
up vote
-1
down vote
You could try this
num <- as.data.frame(num)
num$sub_num <- num[c(2:14, c("0")), ]
num$diff <- num$num - num$sub_num
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
add a comment |Â
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
accepted
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Doing this in a shell loop calling bc
is cumbersome. The above uses a simple awk
script that reads the values off of the file one by one and for any line past the first one, it prints the difference as you describe.
The first block, NR > 1 print $0 - prev
, conditionally prints the difference between this and the previous line if we've reached line two or further (NR
is the number of records read so far, and a "record" is by default a line).
The second block, prev = $0
, unconditionally sets prev
to the value on the current line.
Redirect the output to newfile.dat
to save the result there:
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat >newfile.dat
Related:
- Why is using a shell loop to process text considered bad practice?
There was some mentioning of the slowness of calling bc
in a loop. The following is a way of using a single invocation of bc
to do the arithmetics while still reading the data in a shell loop (I would not actually recommend solving this problem in this way, and I'm only showing it here for people interested in co-processes in bash
):
#!/bin/bash
coproc bc
read prev
while read number; do
printf '%f - %fn' "$number" "$prev" >&"$COPROC[1]"
prev=$number
read -u "$COPROC[0]" result
printf '%fn' "$result"
done
<file.dat >newfile.dat
kill "$COPROC_PID"
The value in $COPROC[1]
is the standard input file descriptor of bc
while $COPROC[0]
is the standard output file descriptor of bc
.
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yodaprev
is the value on the previous line. For the first line, the first block is not executed (due to theNR > 1
condition), soprev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed beforeprev
is set to the value of the second line. The blocks are executed in order, and for each line.
â Kusalananda
Sep 19 at 14:42
@Yoda Soprev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually useprev
, it is the value of the previous line.
â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
add a comment |Â
up vote
9
down vote
accepted
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Doing this in a shell loop calling bc
is cumbersome. The above uses a simple awk
script that reads the values off of the file one by one and for any line past the first one, it prints the difference as you describe.
The first block, NR > 1 print $0 - prev
, conditionally prints the difference between this and the previous line if we've reached line two or further (NR
is the number of records read so far, and a "record" is by default a line).
The second block, prev = $0
, unconditionally sets prev
to the value on the current line.
Redirect the output to newfile.dat
to save the result there:
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat >newfile.dat
Related:
- Why is using a shell loop to process text considered bad practice?
There was some mentioning of the slowness of calling bc
in a loop. The following is a way of using a single invocation of bc
to do the arithmetics while still reading the data in a shell loop (I would not actually recommend solving this problem in this way, and I'm only showing it here for people interested in co-processes in bash
):
#!/bin/bash
coproc bc
read prev
while read number; do
printf '%f - %fn' "$number" "$prev" >&"$COPROC[1]"
prev=$number
read -u "$COPROC[0]" result
printf '%fn' "$result"
done
<file.dat >newfile.dat
kill "$COPROC_PID"
The value in $COPROC[1]
is the standard input file descriptor of bc
while $COPROC[0]
is the standard output file descriptor of bc
.
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yodaprev
is the value on the previous line. For the first line, the first block is not executed (due to theNR > 1
condition), soprev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed beforeprev
is set to the value of the second line. The blocks are executed in order, and for each line.
â Kusalananda
Sep 19 at 14:42
@Yoda Soprev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually useprev
, it is the value of the previous line.
â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
add a comment |Â
up vote
9
down vote
accepted
up vote
9
down vote
accepted
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Doing this in a shell loop calling bc
is cumbersome. The above uses a simple awk
script that reads the values off of the file one by one and for any line past the first one, it prints the difference as you describe.
The first block, NR > 1 print $0 - prev
, conditionally prints the difference between this and the previous line if we've reached line two or further (NR
is the number of records read so far, and a "record" is by default a line).
The second block, prev = $0
, unconditionally sets prev
to the value on the current line.
Redirect the output to newfile.dat
to save the result there:
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat >newfile.dat
Related:
- Why is using a shell loop to process text considered bad practice?
There was some mentioning of the slowness of calling bc
in a loop. The following is a way of using a single invocation of bc
to do the arithmetics while still reading the data in a shell loop (I would not actually recommend solving this problem in this way, and I'm only showing it here for people interested in co-processes in bash
):
#!/bin/bash
coproc bc
read prev
while read number; do
printf '%f - %fn' "$number" "$prev" >&"$COPROC[1]"
prev=$number
read -u "$COPROC[0]" result
printf '%fn' "$result"
done
<file.dat >newfile.dat
kill "$COPROC_PID"
The value in $COPROC[1]
is the standard input file descriptor of bc
while $COPROC[0]
is the standard output file descriptor of bc
.
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat
-0.043962
-0.020674
0.002742
-0.004449
0.011906
-0.026333
0.001461
0.011245
-0.002031
-0.009281
-0.006112
0.011811
-0.004837
Doing this in a shell loop calling bc
is cumbersome. The above uses a simple awk
script that reads the values off of the file one by one and for any line past the first one, it prints the difference as you describe.
The first block, NR > 1 print $0 - prev
, conditionally prints the difference between this and the previous line if we've reached line two or further (NR
is the number of records read so far, and a "record" is by default a line).
The second block, prev = $0
, unconditionally sets prev
to the value on the current line.
Redirect the output to newfile.dat
to save the result there:
$ awk 'NR > 1 print $0 - prev prev = $0 ' <file.dat >newfile.dat
Related:
- Why is using a shell loop to process text considered bad practice?
There was some mentioning of the slowness of calling bc
in a loop. The following is a way of using a single invocation of bc
to do the arithmetics while still reading the data in a shell loop (I would not actually recommend solving this problem in this way, and I'm only showing it here for people interested in co-processes in bash
):
#!/bin/bash
coproc bc
read prev
while read number; do
printf '%f - %fn' "$number" "$prev" >&"$COPROC[1]"
prev=$number
read -u "$COPROC[0]" result
printf '%fn' "$result"
done
<file.dat >newfile.dat
kill "$COPROC_PID"
The value in $COPROC[1]
is the standard input file descriptor of bc
while $COPROC[0]
is the standard output file descriptor of bc
.
edited Sep 19 at 19:20
answered Sep 19 at 14:31
Kusalananda
108k14209332
108k14209332
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yodaprev
is the value on the previous line. For the first line, the first block is not executed (due to theNR > 1
condition), soprev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed beforeprev
is set to the value of the second line. The blocks are executed in order, and for each line.
â Kusalananda
Sep 19 at 14:42
@Yoda Soprev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually useprev
, it is the value of the previous line.
â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
add a comment |Â
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yodaprev
is the value on the previous line. For the first line, the first block is not executed (due to theNR > 1
condition), soprev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed beforeprev
is set to the value of the second line. The blocks are executed in order, and for each line.
â Kusalananda
Sep 19 at 14:42
@Yoda Soprev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually useprev
, it is the value of the previous line.
â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
If prev is the value on the current line, how does this actually work? Because if I substitute prev = $0 into the first block, we get print $0 - $0.
â Yoda
Sep 19 at 14:41
@Yoda
prev
is the value on the previous line. For the first line, the first block is not executed (due to the NR > 1
condition), so prev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed before prev
is set to the value of the second line. The blocks are executed in order, and for each line.â Kusalananda
Sep 19 at 14:42
@Yoda
prev
is the value on the previous line. For the first line, the first block is not executed (due to the NR > 1
condition), so prev
only gets the value of the first line (and nothing else happens). For the second line, the difference between the second and first line is printed before prev
is set to the value of the second line. The blocks are executed in order, and for each line.â Kusalananda
Sep 19 at 14:42
@Yoda So
prev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually use prev
, it is the value of the previous line.â Kusalananda
Sep 19 at 14:57
@Yoda So
prev
is the value on the current line only at the very end of processing that line, before continuing with the next line. When we actually use prev
, it is the value of the previous line.â Kusalananda
Sep 19 at 14:57
I understand now, thank you.
â Yoda
Sep 19 at 15:01
I understand now, thank you.
â Yoda
Sep 19 at 15:01
add a comment |Â
up vote
3
down vote
Using some straightforward GNU utilities, and no shell loops:
paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc
The idea here is to duplicate the input file into two columns; offset the second column by 1 line, and paste the columns together with -
as a separator. head
and tail
are used to trim off the last line of the 1st column and first line of 2nd column respectively, to achieve the necessary offsetting. The resulting list is the required list of arithmetic differences that is piped to bc
for evaluation.
Try it online.
Alternatively, if you like sed
, you can do this:
sed '1s/$/-\/;p;d;$p;d;s/.*/&n&-\/' file.dat | bc
This duplicates each line and inserts -
at the end of the second version of each line. The first and last lines are treated differently to generate the necessary expressions. The sed output ends up something like this:
a-
b
b-
c
c-
d
These again are valid arithmetic differences that bc
can evaluate. Not that bc
understands the line-continuation backslashes at the ends of every other line.
Try it online.
add a comment |Â
up vote
3
down vote
Using some straightforward GNU utilities, and no shell loops:
paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc
The idea here is to duplicate the input file into two columns; offset the second column by 1 line, and paste the columns together with -
as a separator. head
and tail
are used to trim off the last line of the 1st column and first line of 2nd column respectively, to achieve the necessary offsetting. The resulting list is the required list of arithmetic differences that is piped to bc
for evaluation.
Try it online.
Alternatively, if you like sed
, you can do this:
sed '1s/$/-\/;p;d;$p;d;s/.*/&n&-\/' file.dat | bc
This duplicates each line and inserts -
at the end of the second version of each line. The first and last lines are treated differently to generate the necessary expressions. The sed output ends up something like this:
a-
b
b-
c
c-
d
These again are valid arithmetic differences that bc
can evaluate. Not that bc
understands the line-continuation backslashes at the ends of every other line.
Try it online.
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Using some straightforward GNU utilities, and no shell loops:
paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc
The idea here is to duplicate the input file into two columns; offset the second column by 1 line, and paste the columns together with -
as a separator. head
and tail
are used to trim off the last line of the 1st column and first line of 2nd column respectively, to achieve the necessary offsetting. The resulting list is the required list of arithmetic differences that is piped to bc
for evaluation.
Try it online.
Alternatively, if you like sed
, you can do this:
sed '1s/$/-\/;p;d;$p;d;s/.*/&n&-\/' file.dat | bc
This duplicates each line and inserts -
at the end of the second version of each line. The first and last lines are treated differently to generate the necessary expressions. The sed output ends up something like this:
a-
b
b-
c
c-
d
These again are valid arithmetic differences that bc
can evaluate. Not that bc
understands the line-continuation backslashes at the ends of every other line.
Try it online.
Using some straightforward GNU utilities, and no shell loops:
paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc
The idea here is to duplicate the input file into two columns; offset the second column by 1 line, and paste the columns together with -
as a separator. head
and tail
are used to trim off the last line of the 1st column and first line of 2nd column respectively, to achieve the necessary offsetting. The resulting list is the required list of arithmetic differences that is piped to bc
for evaluation.
Try it online.
Alternatively, if you like sed
, you can do this:
sed '1s/$/-\/;p;d;$p;d;s/.*/&n&-\/' file.dat | bc
This duplicates each line and inserts -
at the end of the second version of each line. The first and last lines are treated differently to generate the necessary expressions. The sed output ends up something like this:
a-
b
b-
c
c-
d
These again are valid arithmetic differences that bc
can evaluate. Not that bc
understands the line-continuation backslashes at the ends of every other line.
Try it online.
edited Sep 19 at 17:52
answered Sep 19 at 16:57
Digital Trauma
5,61211528
5,61211528
add a comment |Â
add a comment |Â
up vote
2
down vote
If you wanted to try and force the shell script into working, you were just missing some initialization:
f=myfile.dat
prev=0
while read line; do
bc <<< "$line - $prev"
prev=$line
done < $f > newfile.dat
... where I also moved the redirection outside of the loop, just to save some I/O.
The bc
solution does not print leading zeroes, while the awk solution does.
1
Certainly shell loops are generally slow, but even slower is spawning abc
process for every iteration of the loop. You can simply echo the"$line - $prev"
expression into a pipe which is evaluated bybc
outside of the loop: tio.run/â¦
â Digital Trauma
Sep 19 at 17:02
add a comment |Â
up vote
2
down vote
If you wanted to try and force the shell script into working, you were just missing some initialization:
f=myfile.dat
prev=0
while read line; do
bc <<< "$line - $prev"
prev=$line
done < $f > newfile.dat
... where I also moved the redirection outside of the loop, just to save some I/O.
The bc
solution does not print leading zeroes, while the awk solution does.
1
Certainly shell loops are generally slow, but even slower is spawning abc
process for every iteration of the loop. You can simply echo the"$line - $prev"
expression into a pipe which is evaluated bybc
outside of the loop: tio.run/â¦
â Digital Trauma
Sep 19 at 17:02
add a comment |Â
up vote
2
down vote
up vote
2
down vote
If you wanted to try and force the shell script into working, you were just missing some initialization:
f=myfile.dat
prev=0
while read line; do
bc <<< "$line - $prev"
prev=$line
done < $f > newfile.dat
... where I also moved the redirection outside of the loop, just to save some I/O.
The bc
solution does not print leading zeroes, while the awk solution does.
If you wanted to try and force the shell script into working, you were just missing some initialization:
f=myfile.dat
prev=0
while read line; do
bc <<< "$line - $prev"
prev=$line
done < $f > newfile.dat
... where I also moved the redirection outside of the loop, just to save some I/O.
The bc
solution does not print leading zeroes, while the awk solution does.
answered Sep 19 at 14:40
Jeff Schaller
33.2k849111
33.2k849111
1
Certainly shell loops are generally slow, but even slower is spawning abc
process for every iteration of the loop. You can simply echo the"$line - $prev"
expression into a pipe which is evaluated bybc
outside of the loop: tio.run/â¦
â Digital Trauma
Sep 19 at 17:02
add a comment |Â
1
Certainly shell loops are generally slow, but even slower is spawning abc
process for every iteration of the loop. You can simply echo the"$line - $prev"
expression into a pipe which is evaluated bybc
outside of the loop: tio.run/â¦
â Digital Trauma
Sep 19 at 17:02
1
1
Certainly shell loops are generally slow, but even slower is spawning a
bc
process for every iteration of the loop. You can simply echo the "$line - $prev"
expression into a pipe which is evaluated by bc
outside of the loop: tio.run/â¦â Digital Trauma
Sep 19 at 17:02
Certainly shell loops are generally slow, but even slower is spawning a
bc
process for every iteration of the loop. You can simply echo the "$line - $prev"
expression into a pipe which is evaluated by bc
outside of the loop: tio.run/â¦â Digital Trauma
Sep 19 at 17:02
add a comment |Â
up vote
2
down vote
You could use an exec
redirection to read successive lines of the input file from multiple points in the script - once before the loop (to set up the initial value), then repeatedly during it (for each new value to subtract):
exec 3<file.dat
read prev<&3
while read curr ; do
bc <<< "$curr - $prev" >> newfile.dat
prev=$curr
done <&3
1
Usingread prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.
â Kusalananda
Sep 19 at 15:00
add a comment |Â
up vote
2
down vote
You could use an exec
redirection to read successive lines of the input file from multiple points in the script - once before the loop (to set up the initial value), then repeatedly during it (for each new value to subtract):
exec 3<file.dat
read prev<&3
while read curr ; do
bc <<< "$curr - $prev" >> newfile.dat
prev=$curr
done <&3
1
Usingread prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.
â Kusalananda
Sep 19 at 15:00
add a comment |Â
up vote
2
down vote
up vote
2
down vote
You could use an exec
redirection to read successive lines of the input file from multiple points in the script - once before the loop (to set up the initial value), then repeatedly during it (for each new value to subtract):
exec 3<file.dat
read prev<&3
while read curr ; do
bc <<< "$curr - $prev" >> newfile.dat
prev=$curr
done <&3
You could use an exec
redirection to read successive lines of the input file from multiple points in the script - once before the loop (to set up the initial value), then repeatedly during it (for each new value to subtract):
exec 3<file.dat
read prev<&3
while read curr ; do
bc <<< "$curr - $prev" >> newfile.dat
prev=$curr
done <&3
answered Sep 19 at 14:44
JigglyNaga
2,958624
2,958624
1
Usingread prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.
â Kusalananda
Sep 19 at 15:00
add a comment |Â
1
Usingread prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.
â Kusalananda
Sep 19 at 15:00
1
1
Using
read prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.â Kusalananda
Sep 19 at 15:00
Using
read prev; while ...; do ...; done; <file.dat
, you avoid having to juggle file descriptors.â Kusalananda
Sep 19 at 15:00
add a comment |Â
up vote
0
down vote
I use arrays. I use them for everything. I cannot remember how awk and sed work without extensive study of the man pages. Here is the way I would do it.
f=( $(< file.dat) )
for ((num=1;num<=$#f[@];num++))
do
echo $(bc <<< $f[$num]-$f[(($num-1))])>>differences.dat
done
This is the way I understand it. It has the objectionable features of some of the other answers: looping and calling bc over and over. However, it only reads the file once, like the answers using sed and awk.
add a comment |Â
up vote
0
down vote
I use arrays. I use them for everything. I cannot remember how awk and sed work without extensive study of the man pages. Here is the way I would do it.
f=( $(< file.dat) )
for ((num=1;num<=$#f[@];num++))
do
echo $(bc <<< $f[$num]-$f[(($num-1))])>>differences.dat
done
This is the way I understand it. It has the objectionable features of some of the other answers: looping and calling bc over and over. However, it only reads the file once, like the answers using sed and awk.
add a comment |Â
up vote
0
down vote
up vote
0
down vote
I use arrays. I use them for everything. I cannot remember how awk and sed work without extensive study of the man pages. Here is the way I would do it.
f=( $(< file.dat) )
for ((num=1;num<=$#f[@];num++))
do
echo $(bc <<< $f[$num]-$f[(($num-1))])>>differences.dat
done
This is the way I understand it. It has the objectionable features of some of the other answers: looping and calling bc over and over. However, it only reads the file once, like the answers using sed and awk.
I use arrays. I use them for everything. I cannot remember how awk and sed work without extensive study of the man pages. Here is the way I would do it.
f=( $(< file.dat) )
for ((num=1;num<=$#f[@];num++))
do
echo $(bc <<< $f[$num]-$f[(($num-1))])>>differences.dat
done
This is the way I understand it. It has the objectionable features of some of the other answers: looping and calling bc over and over. However, it only reads the file once, like the answers using sed and awk.
answered Sep 19 at 18:40
Wastrel
11
11
add a comment |Â
add a comment |Â
up vote
-1
down vote
You could try this
num <- as.data.frame(num)
num$sub_num <- num[c(2:14, c("0")), ]
num$diff <- num$num - num$sub_num
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
add a comment |Â
up vote
-1
down vote
You could try this
num <- as.data.frame(num)
num$sub_num <- num[c(2:14, c("0")), ]
num$diff <- num$num - num$sub_num
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
add a comment |Â
up vote
-1
down vote
up vote
-1
down vote
You could try this
num <- as.data.frame(num)
num$sub_num <- num[c(2:14, c("0")), ]
num$diff <- num$num - num$sub_num
You could try this
num <- as.data.frame(num)
num$sub_num <- num[c(2:14, c("0")), ]
num$diff <- num$num - num$sub_num
edited Sep 20 at 5:42
RalfFriedl
4,1331725
4,1331725
answered Sep 20 at 5:16
Harini
1
1
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
add a comment |Â
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
2
2
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
This is not just poorly formatted, it doesn't even specify what programming language is used.
â RalfFriedl
Sep 20 at 5:43
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f470031%2floop-over-lines-in-file-and-subtract-previous-line-from-current-line%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password