Редактируйте значения в текстовом файле с помощью команды sed / awk / grep

9

Уже 5 лет пользуюсь метеостанцией La Crosse WS2350. Данные, предоставленные метеостанцией, обрабатываются с open2300 по RPI. Это работает очень хорошо. Тем не менее, данные о температуре ложные (датчик). Данные о температуре на 1 ° C ниже.

Поскольку я не могу откалибровать датчик, я хочу изменить значение температуры из файла, извлеченного из метеостанции.

Этот текстовый файл (current.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 -2.4
Tomin -4.8
Tomax 37.4
TTomin 06:46
DTomin 2016-02-18
TTomax 16:13
DTomax 2016-07-19
...

Я хочу добавить +1 к значениям «To», «Tomin», «Tomax» и перезаписать текстовый файл правильными значениями.

Посмотрев команды sed и awk, я понял, что устарел. Кто-нибудь может направить меня? Спасибо

Редактировать :

Я забыл другой файл: ws2308.log Каждые 15 минут в файл добавляется новая строка 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 

Значение, которое нужно изменить - это 5-е поле (первое -1.2)

Также необходимо, чтобы в последней строке значение температуры увеличивалось на 1 и перезаписывало последнюю строку правильным значением. Только последняя строка будет учтена программой php, которая позволяет отображать результаты в виде графика.

Спасибо

Ookpik
источник

Ответы:

12

Вот немного более идиоматический вариант AWK для обработки current.txt( второй ответ Стива еще более идиоматичен!):

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

Это ищет строки, начинающиеся с Toнуля minили maxпосле пробела; для сопоставления строк он печатает первое поле и второе поле с приращением, разделенные разделителем поля вывода по умолчанию (пробел). Затем он переходит на следующую строку. Все остальные строки печатаются как есть ( 1для этого есть ярлык в AWK).

Обратите внимание, что перезапись файла новыми значениями, вероятно, не очень хорошая идея: вы не будете знать, были ли значения исправлены или нет ... Если вы извлекаете файл с устройства каждый раз, тогда это не применяется.

То же относится и к рассуждениям ws2308.log, поэтому давайте каждый раз обрабатывать их полностью:

$ 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

Если вы хотите только последнюю строку:

$ 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

или если вы хотите, чтобы файл был изменен только в последней строке :

$ 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
Стивен Китт
источник
10

Вот одно из решений. Для любых строк, начинающихся с «To», «Tomin» или «Tomax», за которыми следует пробел, выведите первое поле, а затем второе поле, увеличенное на 1. В противном случае просто напечатайте полную строку.

$ 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
$
Стив
источник
5

Другой подход, слегка гольф .

$ 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
$
Стив
источник
3
Хорошо (так +1), но вы могли бы просто добавить это в качестве редактирования к вашему существующему ответу!
Стивен Китт
@Scott -iна awkдобавляет инклюдник, это ничего , как sed«S -iвариант.
Стивен Китт
@StephenKitt: D'oh! Я знал это.
Скотт
5

Подход Perl:

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

Он -iзаставляет его перезаписать исходный файл, поэтому он ничего не распечатает, он изменит файл напрямую.

Операторы -aделают perlтак awk, будто их входные данные делятся на whitesapce (или что-либо еще, что дано -F) в массиве @F. Итак, второе поле будет, $F[1]потому что массивы начнут отсчитываться с 0. Поэтому сценарий заменит второе поле на себя, увеличенное на единицу в строках, начинающихся с To.

Тердон
источник
2

Это сделает работу:

  1. Сначала пройдем по всем строчкам
  2. Затем проверьте первый элемент и проверьте, соответствует ли он тому, что вы хотите.
  3. Затем, если он совпадает, выведите его и добавьте +1 к следующему элементу в строке
  4. Иначе просто распечатай и распечатай следующий предмет

    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
    

ВЫВОД

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
Виссам Ружула
источник