ファイルの行を繰り返し、現在の行から前の行を減算します。

ファイルの行を繰り返し、現在の行から前の行を減算します。

数値を含むファイルがあります。

$ 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

現在の行と前の行の違いを含む新しいファイルを作成したいと思います。予想される出力は次のようになります。

$ 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

簡単だと思うので、このコードで始めました。

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

    bc <<< "$line - $prev" >> newfile.dat
done < $f

しかし、私はファイルの前の行にアクセスする方法がわからないことにすぐに気づきました。最初の行を読むときにマイナスがないことを考慮する必要があるようです。進行方法のご案内をいただきありがとうございます!

答え1

$ 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

シェルループ呼び出し内でこれを行うのはbc面倒です。上記は、awkファイルの値を1つずつ読み、最初の行以降のすべての行について説明する違いを印刷する単純なスクリプトを使用しています。

NR > 1 { print $0 - prev }2行目以上(NRこれまでに読んだレコード数、デフォルトでは「レコード」は1行)に達すると、最初のブロックは条件付きでこの行と前の行の違いを印刷します。

2番目のブロック{ prev = $0 }は無条件prevに現在の行の値に設定されます。

newfile.dat結果を保存するには、出力をリダイレクトします。

$ awk 'NR > 1 { print $0 - prev } { prev = $0 }' <file.dat >newfile.dat

関連:


誰かがbcループ呼び出しが遅いと述べました。以下は、シェルループからデータを読み取るときに単一の呼び出しを使用して算術を実行する方法です。bc(私は実際にこの方法で問題を解決することをお勧めしません。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"

の値${COPROC[1]}は標準入力ファイル記述子ですが、標準出力ファイル記述子ではありませんbc${COPROC[0]}bc

答え2

シェルループなしでいくつかの単純なGNUユーティリティを使用する:

paste -d- <(head -n-1 file.dat) <(tail -n+2 file.dat) | bc

ここでのアイデアは、入力ファイルを2つの列にコピーし、2番目の列を1行ずつオフセットし、列を区切り記号-として貼り付けることです。必要なオフセットを達成するために、それぞれ最初の列の最後の行と2番目の列の最初の行を切り取るために使用されますheadtail結果のリストは、bc評価に必要な算術差のリストにリンクされます。

オンラインでお試しください


または、必要に応じてsed次のことを実行できます。

sed '1{s/$/-\\/;p;d};${p;d};s/.*/&\n&-\\/' file.dat | bc

-\これにより、各行がコピーされ、各行の2番目のバージョンの最後に挿入されます。最初の行と最後の行は、必要な式を生成するために異なる方法で処理されます。 sedの出力は次のとおりです。

a-\
b
b-\
c
c-\
d

これは評価できる有効な算術差でもありますbcbc1行ずつ、最後の行連続バックスラッシュは認識されません。

オンラインでお試しください

答え3

シェルスクリプトを強制的に操作したい場合は、一部の初期化がありません。

f=myfile.dat
prev=0
while read line; do
    bc <<< "$line - $prev"
    prev=$line
done < $f > newfile.dat

...また、一部のI / Oを節約するためにループの外にリダイレクトを移動しました。

このbcソリューションは先行ゼロを印刷しませんが、奇妙なソリューションする。

答え4

私は配列を使用します。私はそれをすべてに使用します。マニュアルページを広く研究することなく、awkとsedがどのように機能するか覚えていません。これが私がする方法です。

f=( $(< file.dat) )
for ((num=1;num<=${#f[@]};num++))
do
    echo $(bc <<< ${f[$num]}-${f[(($num-1))]})>>differences.dat
done

これが私が理解する方法です。それは他の答えのいくつかの不快な特性を持っています。つまり、bcを繰り返し繰り返し呼び出します。しかし、sedとawkを使った答えのように、ファイルを一度だけ読みます。

関連情報