47

I am a newbie to linux and I am trying to watch a command and try to log it into a file. I tried

watch -t -n 10 "(date '+TIME:%H:%M:%S' ; ps aux | grep "pattern" | wc -l)" >> logfile

and am expecting a result like

TIME: 10:32:30    12
TIME: 10:32:40    18
TIME: 10:32:50    2

to be stored in logfile. However, when the logfile has unprintable characters in in. How do I get this kind of output from the command li

LoudKur
  • 613
  • 1
  • 5
  • 6

8 Answers8

62

This can easily be done using watch too without using any scripts.

watch -t -n 10 "(date '+TIME:%H:%M:%S' ; ps aux | grep "pattern" | wc -l) | tee -a logfile"

  • 1
    Correct. I wrote what I had on a Mac, where watch isn't available out of the box, and opted for the portable solution. Yours is much simpler. – Kirk Aug 27 '13 at 13:17
  • 9
    In other words, include a pipe to `tee -a logfile` *within* the arg passed to `watch`. Very clean, thank you. – Wildcard Nov 18 '15 at 22:15
  • 1
    Thanks @Wildcard for your comment, I hadn't notice that the double quotes included the tee command and, that actually help solving my remaining problem – Gonzalo Vasquez Aug 24 '21 at 14:42
34

In order to do what you are looking for, a simple script (as @Ignacio pointed out) should do the trick:

while true
do
    echo "$(date '+TIME:%H:%M:%S') $(ps aux | grep "pattern" | wc -l)" | tee -a logfile
    sleep 2
done

I use tee instead of >> so that you can see the output on your terminal as well as capture it in your log.

Kirk
  • 2,382
  • 17
  • 19
  • I seem to be getting an error with the 1 in the first line. But when I changed it to true, it worked. However the output on the screen shows Time and count on two different lines, but the log file just shows the count only. Is there any way I can get Time and count on the same line in the logfile? – LoudKur Jun 15 '11 at 13:46
  • Ah right, because the tee command is only running for `ps`. I will modify my answer. – Kirk Jun 15 '11 at 14:25
  • Works perfectly! Thanks. Is there any way I can add the timestamp to the logfile so that it gets stored in unique files? – LoudKur Jun 15 '11 at 14:42
  • You mean to the logfile name? You can do something like logfile.$(date +%Y%m%d) to create a new logfile every day. – Kirk Jun 15 '11 at 17:42
  • Ya, I did that. Attached the code as an answer to this question. Thanks! – LoudKur Jun 15 '11 at 19:23
20

watch is meant for output to a display. If you simply want to run a command every X seconds then you should just use a delay loop for that.

while true ; do somecommand ; sleep 2 ; done
Ignacio Vazquez-Abrams
  • 111,361
  • 10
  • 201
  • 247
7

watch is an ncurses program, and is designed to be run in a console window (not redirected), which is why it's creating a bunch of unprintable characters (those are the control characters that manage and move the cursor around for redrawing the screen).

You might try moving the date / grep commands into a script, and then call that script from a cronjob.

Darth Android
  • 37,872
  • 5
  • 94
  • 112
4

Ok, so I put it in a script and have the following code:

#!/bin/sh
NOW=$(date '+%Y%m%d%H%M%S')
LOGFILE="log.$NOW"

while true
do
    echo $(date '+[TIME: %H:%M:%S]   Output: ' ; ps aux | grep "pattern" | wc -l ) | tee -a $LOGFILE
    sleep 2
done
LoudKur
  • 613
  • 1
  • 5
  • 6
2

One easy alternative would be putting the command in a cmd.sh file with the following content:

#!/bin/bash
(date '+TIME:%H:%M:%S' ; ps aux | grep "apache" | wc -l) >> logfile

And then just run:

watch -t -n 10 ./cmd.sh
Pablo Santa Cruz
  • 1,729
  • 17
  • 22
1

I came across this question when I was trying to get better/logged output from du -sh $data_path. I used the "while command, do sleep" pattern found here, but used some complex AWK to give the output I wanted.

while du -sh $data_path; do sleep 1; done | awk '
$1 != size {
    size=$1;
    path=$2;
    time=systime();
    seconds=time-prevtime;
    if(seconds < 1000000000){
        seconds=seconds" seconds"
    }else{
        seconds=""
    }
    print size, path, strftime("%m/%d/%Y@%H:%M:%S", time), seconds; 
    prevtime=time
}'

I actually did this as a oneliner, which is why there are semicolons. But to make it readable, I broke it out. The output looks like:

502G /var/lib/cassandra/dump/ 05/22/2018@04:46:17
503G /var/lib/cassandra/dump/ 05/22/2018@04:46:59 42 seconds
504G /var/lib/cassandra/dump/ 05/22/2018@04:47:57 58 seconds
505G /var/lib/cassandra/dump/ 05/22/2018@04:48:55 58 seconds
506G /var/lib/cassandra/dump/ 05/22/2018@04:49:53 58 seconds
507G /var/lib/cassandra/dump/ 05/22/2018@04:50:50 57 seconds
508G /var/lib/cassandra/dump/ 05/22/2018@04:51:46 56 seconds
509G /var/lib/cassandra/dump/ 05/22/2018@04:52:44 58 seconds
510G /var/lib/cassandra/dump/ 05/22/2018@04:53:41 57 seconds
Bruno Bronosky
  • 1,885
  • 1
  • 20
  • 26
0

Here is an example I just needed for a watch on a ps axf with a timestamp at the bottom of the entire output. I am watching for when Apache fails. I had to pipe to tee for each command, the ps and the date.

watch 'ps axf | grep --line-buffered "[a]pache2"| tee --append logfile-apache-issue.log; date '+TIME:%H:%M:%S' | tee --append logfile-apache-issue.log'

Sample Output of tail --follow logfile-apache-issue.log on the resulting file.

29862 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29863 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29864 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29865 ?        S      0:00          \_ /usr/sbin/apache2 -k start
26635 pts/2    S+     0:00  |       \_ tail -n 1000 -f /var/log/apache2/error.log
TIME:02:21:13
13622 ?        SN     0:33      \_ /usr/sbin/apache2 -k start
25038 ?        Ss     0:01      \_ /usr/sbin/apache2 -k start
29859 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29860 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29861 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29862 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29863 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29864 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29865 ?        S      0:00          \_ /usr/sbin/apache2 -k start
26635 pts/2    S+     0:00  |       \_ tail -n 1000 -f /var/log/apache2/error.log
TIME:02:21:15
13622 ?        SN     0:33      \_ /usr/sbin/apache2 -k start
25038 ?        Ss     0:01      \_ /usr/sbin/apache2 -k start
29859 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29860 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29861 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29862 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29863 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29864 ?        S      0:00          \_ /usr/sbin/apache2 -k start
29865 ?        S      0:00          \_ /usr/sbin/apache2 -k start
26635 pts/2    S+     0:00  |       \_ tail -n 1000 -f /var/log/apache2/error.log
TIME:02:21:16
Elijah Lynn
  • 1,444
  • 3
  • 17
  • 26