数値を含むファイルがあります。
$ 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番目の列の最初の行を切り取るために使用されますhead
。tail
結果のリストは、bc
評価に必要な算術差のリストにリンクされます。
または、必要に応じてsed
次のことを実行できます。
sed '1{s/$/-\\/;p;d};${p;d};s/.*/&\n&-\\/' file.dat | bc
-\
これにより、各行がコピーされ、各行の2番目のバージョンの最後に挿入されます。最初の行と最後の行は、必要な式を生成するために異なる方法で処理されます。 sedの出力は次のとおりです。
a-\
b
b-\
c
c-\
d
これは評価できる有効な算術差でもありますbc
。bc
1行ずつ、最後の行連続バックスラッシュは認識されません。
答え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を使った答えのように、ファイルを一度だけ読みます。