循环文件中的行并从当前行减去前一行

Yod*_*oda 5 scripting bash shell-script

我有一个包含一些数字的文件

$ 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
Run Code Online (Sandbox Code Playgroud)

我想创建一个新文件,其中包含当前行与前一行的差异。预期输出应该是

$ 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
Run Code Online (Sandbox Code Playgroud)

认为这是微不足道的,我从这段代码开始

f="myfile.dat"    
while read line; do
    curr=$line
    prev=

    bc <<< "$line - $prev" >> newfile.dat
done < $f
Run Code Online (Sandbox Code Playgroud)

但我很快意识到我不知道如何访问文件中的前一行。我想我还需要考虑到在阅读第一行时不应该进行减法。任何有关如何进行的指导表示赞赏!

Kus*_*nda 11

$ 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
Run Code Online (Sandbox Code Playgroud)

在 shell 循环调用中执行此操作bc很麻烦。上面使用了一个简单的awk脚本,它逐行读取文件中的值,对于第一行之后的任何行,它会按照您的描述打印差异。

NR > 1 { print $0 - prev }如果我们到达第二行或更远的行(NR是到目前为止读取的记录数,并且“记录”默认为一行),则第一个块有条件地打印此行与前一行之间的差异。

第二个块,{ prev = $0 },无条件地设置prev为当前行上的值。

将输出重定向到newfile.dat以将结果保存在那里:

$ awk 'NR > 1 { print $0 - prev } { prev = $0 }' <file.dat >newfile.dat
Run Code Online (Sandbox Code Playgroud)

有关的:


有人提到bc在循环中调用很慢。下面是一种使用单个调用bc来进行算术运算的方法,同时仍然在 shell 循环中读取数据(我实际上不建议以这种方式解决这个问题,我只是在这里向对 co 感兴趣的人展示它- 处理bash):

#!/bin/bash

coproc bc

{
    read prev

    while read number; do
        printf '%f - %f\n' "$number" "$prev" >&"${COPROC[1]}"
        prev=$number

        read -u "${COPROC[0]}" result
        printf '%f\n' "$result"
    done
} <file.dat >newfile.dat

kill "$COPROC_PID"
Run Code Online (Sandbox Code Playgroud)

in 的值${COPROC[1]}是 的标准输入文件描述符,bc${COPROC[0]}是 的标准输出文件描述符bc