0

I'm supposed to follow a logfile, I want to initiate a sed command to edit conffile upon appearance of certain line in the log. I did little research and found out that it can be done with awk.

and the syntax is like:

tail -f /path/to/serverLog | awk '
                    /Printer is on fire!/ { system("shutdown -h now") }
                    /new USB high speed/  { system("echo \"New USB\" | mail admin") }'

as proposed in this answer

so I wrote my own like with a sed variant:

tail -f logfile | awk '/^Jit ended**/  { system("sed -E '/^Jit/{s/enabled=false/enabled=true/; s/From=[0-9]+-[0-9]+-[0-9]+/From=2021-02-01/}' conffile") }'

but it doesn't work, and throws errors like

(^ syntax error|^ unterminated string)

I guess this is to do something with {} in the sed command not getting compatible with awk syntax, but no idea where exactly, and how to get it work.

Sollosa
  • 1,929
  • 4
  • 20
  • 38

2 Answers2

3

By calling awk to call other commands you're doing:

shell { awk { system { subshell { cmd } } } }

instead of simply

shell { cmd }

which is very inefficient and fragile.

Best I can tell you should just be doing something like (untested):

while IFS= read -r line; do
    case $line in
        *"Printer is on fire!"* ) shutdown -h now ;;
        *"new USB high speed"* )  echo 'New USB' | mail admin ;;
        "Jit ended"* )            tmp=$(mktemp) &&
                                  sed 's/foo/bar/' conffile > "$tmp" &&
                                  mv -- "$tmp" conffile
                                  ;;
    esac
    sleep 1
done < '/path/to/serverLog'
Ed Morton
  • 31,617
  • Thanks Ed, this code seems promising, but it looks like input redirection only reads logfile single time, whereas I need it to follow logfile, till it finds required occurence of the text. – Sollosa Oct 05 '21 at 18:12
  • 2
    @Sollosa There is nothing stopping you from piping tail -f logfile into the loop instead of reading from the log with a redirection. – Kusalananda Oct 05 '21 at 18:22
  • @they I'm using this syntax, done < <(tail -f logfile) but it's not reading logfile instead it throws syntax error – Sollosa Oct 05 '21 at 19:14
  • 2
    @Sollosa Possibly because you are running the script with the wrong interpreter (sh instead of bash?). In any case, why don't you try what you used in the question and what I alluded to when I suggested piping the input from tail, i.e. tail -f logfile | while ...; do ...; done – Kusalananda Oct 05 '21 at 19:19
1

You can use GNU awk's replacement function sub, given the sample input from your previous question, and using the inplace extension to write the file (always do a backup before executing your command):

$ cat conffile
Jit .... enabled=false
Jit ..shoes.. From=2021-01-01
Jit ..gloves.. From=2021-01-01

$ tail -f logfile | while IFS= read -r i; do 
  if echo "$i" | grep '^Jit'; then
    awk -i inplace '/^Jit/ { sub(/=false$/, "=true"); sub(/[0-9\-]+$/, "2021-02-01"); print  }' conffile
    exit # exit if a match is found
  fi
done
$ cat conffile
Jit .... enabled=true
Jit ..shoes.. From=2021-02-01
Jit ..gloves.. From=2021-02-01

I should add my commentary from my answer to that question regarding the substitution:

I propose a solution assuming (until more comprehensive sample input) that the lines have strict end patterns. If that's the case it wouldn't be necessary more complex matching.

And a note: I'm using grep because I'm not savvy enough with awk, I'm sure other answers will be much better (and this one criticized or corrected), but maybe you can get a glimpse of what you can do.