Search code examples
bashshellcron

Insert or update a row in a text file


I want to write a value to a text file with a timestamp. The data/value gets updated every few minutes, but I only want to record the last value and its date. The next day I want to start again with a new line but keeping the previous value. The output will then be charted showing daily values.

I can do this with an if, then, else loop, but I imagine there's a more elegant awk, sed, 'something' solution.

This will be run by a cron job.

Day 1. Every 5 minutes insert a row with $date, $value

During the same day keep updating that row

Day 2. Insert a new row and repeat

Desired output

Day 1 10am

2021-08-17, 5.20

Day 1 11pm

2021-08-17, 12.10

Day 2 10am

2021-08-17, 12.10
2021-08-18, 4.90

Day 2 11pm

2021-08-17, 12.10
2021-08-18, 13.10

Solution

  • One idea would be to skip/ignore/delete the line with today's date (if it exists) and then append a new line with today's date.

    Sample data file:

    $ cat date.log
    2021-08-14, 23.1
    2021-08-15, 17.3
    2021-08-16, 9.3
    
    $ today=$(date '+%Y-%m-%d')
    $ echo $today
    2021-08-17
    
    $ newvalue=13.2
    

    One sed idea to implement this logic:

    $ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
    

    Where:

    • -i -n -e - -inplace update of source file, -n suppress automatic printing of pattern space, -e designate a piece of script
    • "/^${today}, .*$/" - search for pattern that matches (start of line) + ${today} + , + rest of line; need to use double quotes so that ${today} is replaced with it's actual value
    • '!p' - reverse pattern search and print line (ie, print everything but line that matches ^${today}, .*$); need to use single quotes since !p in double quotes will be replaced with the last history command that started with the letter p
    • -e '$a' - another piece of script that finds end of file ($) and appends the following string; must use single quotes so that bash doesn't try to replace the literal $a with the contents of variable a
    • "${today}, ${newvalue}" - string to append to end of file

    If we preface our sed call with set -xv (enable debug mode) we see the following is printed at the console:

    + sed -i -n -e '/^2021-08-17, .*$/!p' -e '$a2021-08-17, 13.2' date.log
    

    And the contents of our file:

    $ cat date.log
    2021-08-14, 23.1
    2021-08-15, 17.3
    2021-08-16, 9.3
    2021-08-17, 13.2              # new line appended to file
    

    A couple more runs (after issuing set +xv to disable debug mode):

    $ newvalue=32.7
    $ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
    $ cat date.log
    2021-08-14, 23.1
    2021-08-15, 17.3
    2021-08-16, 9.3
    2021-08-17, 32.7              # updated (really deleted and appended)
    
    $ newvalue=73.xxx
    $ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
    $ cat date.log
    2021-08-14, 23.1
    2021-08-15, 17.3
    2021-08-16, 9.3
    2021-08-17, 73.xxx            # updated (really deleted and appended)
    
    $ today='2021-09-23'
    $ newvalue=7.25
    $ sed -i -n -e "/^${today}, .*$/"'!p' -e '$a'"${today}, ${newvalue}" date.log
    $ cat date.log
    2021-08-14, 23.1
    2021-08-15, 17.3
    2021-08-16, 9.3
    2021-08-17, 73.xxx
    2021-09-23, 7.25              # new line appended to file