I have client filtering out data from an live MQTT stream which writes the data into a myfile.csv file, here are the last four lines:


This file constantly gets updated. So the last line of the csv file would constantly be changing however it would still be in the same format.

Q: How can I read the last line where the 7th value is 'status' not 'SVlts' of the myfile.csv file with bash? Once read how can I assign the 4th, 5th and 10th value to a 3 different variables? I will be pushing these values out to update a MySQL table.

So the output can be something as follows:


As mentioned these three variables will be pushed/sent out to update a MySQL table (which needs these three variables in order to update itself) until the next line is printed in to the myfile.csv. And this will happen over and over again.

  • If the file is constantly changing, be sure that it gets replaced atomically, not edited in place. That means that the thing that modifies it should generate a new version in a temporary file, then rename the temporary file over the true file. Otherwise readers may access a partially written file if they read happens concurrently with the update. A partially written file will appear to be corrupt.
    – Celada
    Mar 12, 2015 at 5:48

3 Answers 3


This captures the information that you want from the last line of file:

$ IFS=, read -r a b c var_1 var_2 d e f h var_3 extra < <(tail -n1 file)
$ echo $var_1  $var_2  $var_3
TMX6BP 075 179583

How it works

  • IFS=,

    This temporarily sets the field separator to a comma.

  • read -r a b c var_1 var_2 d e f h var_3 extra

    This reads in the fields to the listed variables. You can choose any names you like.

    In the above, the first field is assigned to the shell variable a, the second to b, etc. Everything left over after var_3 is assigned to the shell variable extra.

  • < <(tail -n1 file)

    This provides the last line of file as standard input to the read command. The first < is the shell symbol for redirection. The construct <(...) is called process substitution. The space between the first and second < is essential.


Short answer:

   # tail -F: output appended data as the file grows
   #      Capital F to follow even if the file is reset to zero, recreated, etc.
   # awk -F, sets FS - Field Separator to a comma
   #   Inside awk: See if field 7 == "status" and print fields 4, 5 and 10
tail -F myfile.csv | awk -F, '$7 == "status" { print $4, $5, $10 }'

You are not writing how you will update your database so I'll write up something which might get you started.

It's also my understanding that you will NOT edit the myfile.csv file, but use the 3 mentioned variables as input to an update script/job. Error checking, etc, I'll leave to you.

First, create the script which updates your MySQL database. I'll just mock it here.

# update-MySQL-table.sh
    # redirecting stderr to stdout so awk will see it.
    # Not much use with "echo", but ...
echo $0 $1 $2 $3 2>&1

Then you have another script which reads and parses your CSV file, and starts the database update script.

# parse-my-CSV-file.sh

tail -n0 -F $csvfile | \
    awk -F, '
        $7 == "status" {
            cmd=sprintf("./update-MySQL-table.sh %s %s %s",$4,$5,$10)
            cmd | getline output
            print output

You then start the parse-script, and you should see how new lines added to myfile.csv with "status" in the 7th field are printed to stdout.


I'd do something like:

tail -n1 -f file | 
  perl -MDBI -F, -lane 'BEGIN{$d = DBI->connect(...)}
    if ($F[6] eq "status") {
      $d->do("INSERT INTO foo VALUES (?,?,?)", @F[3,4,9]);

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .