Bash command to copy a log file to another directory as soon as specified expression is found in it

Viewed 37

I've got a log file that is rotated automatically when it reaches a certain size. The system keeps 5 rotated logs at a time, the older ones are deleted, and the lifetime of a log file is about 20 minutes.

The task is to monitor the log file (system.log) for a specified error code and when it occurs – to copy the file into another directory, before it is deleted.

I tried this:

tail -F system.log | grep -l "error code" | xargs cp /another/directory 

but it returns "cp: taget 'input)' is not a directory"

Apparently this is because grep command does not return the file name as soon as the error code is found in it as I expected.

So I need some help here please.

2 Answers

The normal order of arguments to cp is

cp source destination

xargs puts its arguments at the end of the command, so you're executing the command

cp /another/directory input

which has to arguments backwards.

To solve this, use the -t option to cp to specify the destination explicitly.

xargs cp -t /another/directory

I tried this tail -F system.log | grep -l "error code" | xargs -i cp {} /another/directory and it returned 'cp: cannot stat '(standard input)': no such file or directory' It seems that something is wrong with the part tail -F system.log | grep -l "error code" as it returns (standard input) instead of the name of the file

Oops. I can't believe I didn't see that before...

$: echo foo | grep -l foo
(standard input)

tail is sending the file to grep, so grep's file IS stdin, so that's what it's listing.

edit

Are you using logrotate?
Check out the manual and look carefully at the prerotate/postrotate/firstaction/lastaction options.

For an example, Option 7 here -
have your script scan the just-rotated log, and if it has the trigger string in it, copy it somewhere.

Related