Edit nilai dalam file txt dengan perintah sed / awk / grep

9

Selama 5 tahun, saya menggunakan stasiun cuaca La Crosse WS2350. Data yang disediakan oleh stasiun cuaca diproses dengan open2300 pada RPI. Ini bekerja dengan sangat baik. Namun, data suhu salah (sensor). Data suhu lebih rendah 1 ° C.

Karena saya tidak dapat mengkalibrasi sensor, saya ingin mengubah nilai suhu dari file yang diekstrak dari stasiun cuaca.

File teks ini (current.txt) berisi:

Date 2016-Dec-03
Time 10:30:29
Ti 11.9
Timin 11.6
Timax 27.7
TTin 10:34
DTimin 2016-01-19
TTimax 00:44
DTimax 2016-08-28
To -2.4
Tomin -4.8
Tomax 37.4
TTomin 06:46
DTomin 2016-02-18
TTomax 16:13
DTomax 2016-07-19
...

Saya ingin menambahkan +1 ke nilai "Ke", "Tomin", "Tomax" dan menimpa file teks dengan nilai yang benar.

Setelah melihat perintah sed dan awk, saya menyadari bahwa saya sudah ketinggalan zaman. Adakah yang bisa membimbing saya? Terima kasih

Edit:

Saya lupa file lain: ws2308.log Setiap 15 menit baris baru ditambahkan ke file ws2308.log:

...
20161203150600 2016-Dec-03 15:06:00 11.8 -1.1 -3.2 65 87 0.0 157.5 SSE -1.1 569.80 1015.700 
20161203152100 2016-Dec-03 15:21:00 12.3 -1.1 -3.2 64 87 0.0 157.5 SSE -1.1 569.80 1015.600 
20161203153600 2016-Dec-03 15:36:00 12.2 -1.2 -3.3 64 87 0.0 135.0 SE -1.2 569.80 1015.700 

Nilai yang akan diubah adalah bidang ke-5 (yang pertama -1.2)

Juga perlu bahwa pada baris terakhir, nilai suhu bertambah 1 dan menimpa baris terakhir dengan nilai yang benar. Hanya baris terakhir yang akan diperhitungkan oleh program php yang memungkinkan untuk menampilkan hasil dalam grafik.

Terima kasih

Ookpik
sumber

Jawaban:

12

Berikut varian AWK yang sedikit lebih idiomatis untuk diproses current.txt( jawaban kedua steve bahkan lebih idiomatis!):

awk '/^To(|min|max) / { print $1, $2 + 1; next } 1' current.txt

Ini mencari garis yang dimulai dengan To, diikuti oleh tidak ada min, atau maxdiikuti oleh spasi; untuk garis yang cocok itu mencetak bidang pertama dan bidang kedua, bertambah, dipisahkan oleh pemisah bidang keluaran default (spasi). Kemudian melompati ke baris berikutnya. Semua baris lainnya dicetak apa adanya ( 1adalah jalan pintas untuk ini dalam AWK).

Perhatikan bahwa menimpa file dengan nilai-nilai baru mungkin bukan ide yang baik: Anda tidak akan tahu apakah nilai-nilai telah diperbaiki atau tidak ... Jika Anda mengambil file dari perangkat setiap kali maka itu tidak berlaku.

Alasan yang sama berlaku untuk ws2308.log, jadi mari kita proseskan secara keseluruhan setiap waktu:

$ awk 'NF >= 5 { $5 = $5 + 1 } 1' ws2308.log
20161203150600 2016-Dec-03 15:06:00 11.8 -0.1 -3.2 65 87 0.0 157.5 SSE -1.1 569.80 1015.700
20161203152100 2016-Dec-03 15:21:00 12.3 -0.1 -3.2 64 87 0.0 157.5 SSE -1.1 569.80 1015.600
20161203153600 2016-Dec-03 15:36:00 12.2 -0.2 -3.3 64 87 0.0 135.0 SE -1.2 569.80 1015.700

Jika Anda hanya menginginkan baris terakhir:

$ awk 'NF >= 5 { $5 = $5 + 1; lastline = $0 } END { print lastline }' ws2308.log
20161203153600 2016-Dec-03 15:36:00 12.2 -0.2 -3.3 64 87 0.0 135.0 SE -1.2 569.80 1015.700

atau jika Anda ingin file hanya dengan baris terakhir diubah :

$ awk 'length(prevline) > 0 { print prevline } NF >= 5 { prevline = $0; $5 = $5 + 1; lastline = $0 } END { print lastline }' ws2308.log
20161203150600 2016-Dec-03 15:06:00 11.8 -1.1 -3.2 65 87 0.0 157.5 SSE -1.1 569.80 1015.700 
20161203152100 2016-Dec-03 15:21:00 12.3 -1.1 -3.2 64 87 0.0 157.5 SSE -1.1 569.80 1015.600 
20161203153600 2016-Dec-03 15:36:00 12.2 -0.2 -3.3 64 87 0.0 135.0 SE -1.2 569.80 1015.700
Stephen Kitt
sumber
10

Inilah salah satu solusinya. Untuk setiap baris yang dimulai dengan "To", "Tomin" atau "Tomax" diikuti oleh spasi, cetak bidang pertama dan kemudian bidang kedua bertambah dengan 1. Jika tidak, cukup cetak baris penuh.

$ awk '{if(/^(To|Tomin|Tomax) /){print $1 " " $2+1}else{print $0}}' w.txt
Date 2016-Dec-03
Time 10:30:29
Ti 11.9
Timin 11.6
Timax 27.7
TTin 10:34
DTimin 2016-01-19
TTimax 00:44
DTimax 2016-08-28
To -1.4
Tomin -3.8
Tomax 38.4
TTomin 06:46
DTomin 2016-02-18
TTomax 16:13
DTomax 2016-07-19
$
steve
sumber
5

Pendekatan lain, sedikit golf .

$ awk '/^To/{$2++}1' w.txt
Date 2016-Dec-03
Time 10:30:29
Ti 11.9
Timin 11.6
Timax 27.7
TTin 10:34
DTimin 2016-01-19
TTimax 00:44
DTimax 2016-08-28
To -1.4
Tomin -3.8
Tomax 38.4
TTomin 06:46
DTomin 2016-02-18
TTomax 16:13
DTomax 2016-07-19
$
steve
sumber
3
Bagus (jadi +1), tetapi Anda bisa menambahkannya sebagai edit untuk jawaban yang ada!
Stephen Kitt
@Scott -ipada awkmenambahkan include file, tidak ada itu seperti sed's -ipilihan.
Stephen Kitt
@StephenKitt: D'oh! Saya tahu itu.
Scott
5

Pendekatan Perl:

perl -i -ape '/^To/ && s/$F[1]/$F[1]+1/e' file

Itu -imembuatnya menimpa file asli, sehingga tidak akan mencetak apa-apa, itu akan mengubah file secara langsung.

The -amerek perlbertindak seperti awk, membelah masukan pada whitesapce (atau apa pun yang diberikan oleh -F) ke dalam array @F. Jadi, bidang kedua akan $F[1]karena array mulai menghitung pada 0. Karena itu skrip akan menggantikan bidang kedua dengan itu sendiri bertambah dengan satu pada baris dimulai dengan To.

terdon
sumber
2

Ini akan melakukan pekerjaan:

  1. Pertama akan melewati semua jalur
  2. Kemudian periksa item pertama dan periksa apakah cocok dengan yang Anda inginkan.
  3. Kemudian, jika cocok, cetak dan tambahkan +1 ke item berikutnya dalam baris
  4. Lain cetak saja dan cetak item berikutnya

    awk '{
        for(i=1;i<=NF;i++) {
                t+=$i;if(i==1){
                        if($i=="To" ||$i=="Tomin" ||$i=="Tomax"  ){
                                printf  "%s ",$i;
                                print $(i+1)+1;}
    
                        else{
                                print $0
                                }
                        }
                        };
        }' current.txt
    

KELUARAN

Date 2016-Dec-03
Time 10:30:29
Ti 11.9
Timin 11.6
Timax 27.7
TTin 10:34
DTimin 2016-01-19
TTimax 00:44
DTimax 2016-08-28
To -1.4
Tomin -3.8
Tomax 38.4
TTomin 06:46
DTomin 2016-02-18
TTomax 16:13
DTomax 2016-07-19
Wissam Roujoulah
sumber