<p>I implemented this in node.js - I don't know of a unix utility that can dynamically change grep. Here is how it works:</p>

<p><em>before dygrep:</em></p>

<pre><code>many-child-procs &gt; logfile.log                  # in terminal 1
tail -f logfile.log | grep &lt;expression&gt;          # in terminal 2
</code></pre>

<p><em>after dygrep:</em></p>

<pre><code>many-child-procs | dygrep                    # in terminal 1
</code></pre>

<p>then you connect to dygrep with a tcp-client and control which expressions are filtered on.</p>

<p>The following node.js process reads from stdin, and uses a tcp connection to listen for expressions to filter on. For each line of stdin, it only forwards that to stdout if it matches one of the current regular expressions stored in memory.</p>

<pre><code>#!/usr/bin/env node
'use strict';

import * as readline from 'readline';
import * as net from 'net';
import chalk from 'chalk';
import {createParser} from "./json-parser";
import log from './logger';

let port = 4900;


const rl = readline.createInterface({
  input: process.stdin.resume()
});

const regex = new Map&lt;string, RegExp&gt;();

rl.on('line', l =&gt; {

  if (regex.size &lt; 1) {
    process.stdout.write(l + '\n');
    return;
  }

  for (let [k, v] of regex) {
    if (v.test(l)) {
      process.stdout.write(chalk.magenta(' (filtered) ') + l + '\n');
      break;
    }
  }

});

interface IncomingTCPMessage {
  command: {
    add: string,
    remove: string,
    list: boolean,
    removeall: boolean
  }
}

const server = net.createServer(s =&gt; {

  const sendMessage = (m: any) =&gt; {
    s.write(JSON.stringify({message: m}) + `\n`);
  };

  s.pipe(createParser()).on('data', (d: IncomingTCPMessage) =&gt; {

    if (!d.command) {
      log.error('No "command" field was found:', d);
      return ''
    }

    const c = d.command;

    if (c.list) {
      sendMessage({regexes: Array.from(regex.keys()).map(k =&gt; ({regex: regex.get(k), str: k}))});
      log.info('Listing all regex for the client.');
      return;
    }

    if (c.removeall) {
      regex.clear();
      sendMessage(`Cleared all regex.`);
      log.info('Cleared all regex.');
      return;
    }

    if (c.add) {
      regex.set(c.add, new RegExp(c.add));
      sendMessage(`Added regex: ${c.add}.`);
      log.info('Added regex:', c.add);
      return;
    }

    if (c.remove) {
      regex.delete(c.remove);
      sendMessage(`Deleted regex: ${c.remove}.`);
      log.info('Removed regex:', c.remove);
      return;
    }

    log.error('No matching field was found:', d);
    log.info('Regex:', regex);

  });

});

server.listen(port);
</code></pre>

<p>to see the complete code, see:
<a href="https://github.com/ORESoftware/dygrep" rel="nofollow noreferrer">https://github.com/ORESoftware/dygrep</a></p>

CC BY-SA 4.0
2018-09-14T21:48:14.687Z
2018-09-15T22:44:30.643Z
2018-09-15T22:44:30.643Z
Alexander Mills
<p>when tailing a log file, we might use:</p>

<pre><code>tail -f foo.log | grep bar
</code></pre>

<p>if we want to change the grep argument, we have to ctrl-c and then change the argument and then restart the command.</p>

<p>my question is - is there a way to dynamically change what we are grepping for without having to kill the tail/grep commands?</p>

<p>Also looking for a way to do this with <code>less</code> instead of <code>tail</code> if possible.</p>

CC BY-SA 4.0
2018-09-14T20:40:53.853Z
This belongs to Unix, SuperUser or one of the other sysadmin SE sites. But honestly, the question is asking for solution to a problem you don't mention. Why is it a problem to kill/ctl-c the process? Why do you need less? As it reads it sounds like: I'd like to load christmas tree on the roof without leaving the car. I would prefer to do it with Jaguar XKD (does not even have a roof).
Jiri Klouda
CC BY-SA 4.0
2018-09-14T21:30:49.183Z
@alexanderMills could you explain why you need this? I wonder whether this is possible by using another tool, but I think that all of them have to be restarted. Please correct me if I am wrong, but you would like to replace `bar` without stopping the tail process?
030
CC BY-SA 4.0
2018-09-14T21:45:34.253Z
Basically when writing stdout/stderr to a terminal instead of to a log file, I want to have one fewer terminal sessions open
Alexander Mills
<logging>
Dynamically grep with less/tail
Alexander Mills
# Dynamically grep with less/tail

(Asked by: username_0 on 2018-09-13)

when tailing a log file, we might use:
tail -f foo.log | grep bar

if we want to change the grep argument, we have to ctrl-c and then change the argument and then restart the command.
my question is - is there a way to dynamically change what we are grepping for without having to kill the tail/grep commands?
Also looking for a way to do this with less instead of tail if possible.

**Tags:** logging

> **Comments:**
> **username_1**: This belongs to Unix, SuperUser or one of the other sysadmin SE sites. But honestly, the question is asking for solution to a problem you don't mention. Why is it a problem to kill/ctl-c the process? Why do you need less? As it reads it sounds like: I'd like to load christmas tree on the roof without leaving the car. I would prefer to do it with Jaguar XKD (does not even have a roof).  
> **username_2**: @alexanderMills could you explain why you need this? I wonder whether this is possible by using another tool, but I think that all of them have to be restarted. Please correct me if I am wrong, but you would like to replace `bar` without stopping the tail process?  
> **username_0**: Basically when writing stdout/stderr to a terminal instead of to a log file, I want to have one fewer terminal sessions open  

---

## 1 answers

### Answer by username_0 on 2018-09-14. Score: 3 | Accepted answer

I implemented this in node.js - I don't know of a unix utility that can dynamically change grep. Here is how it works:
before dygrep:
many-child-procs > logfile.log                  # in terminal 1
tail -f logfile.log | grep           # in terminal 2

after dygrep:
many-child-procs | dygrep                    # in terminal 1

then you connect to dygrep with a tcp-client and control which expressions are filtered on.
The following node.js process reads from stdin, and uses a tcp connection to listen for expressions to filter on. For each line of stdin, it only forwards that to stdout if it matches one of the current regular expressions stored in memory.
#!/usr/bin/env node
'use strict';

import * as readline from 'readline';
import * as net from 'net';
import chalk from 'chalk';
import {createParser} from "./json-parser";
import log from './logger';

let port = 4900;


const rl = readline.createInterface({
  input: process.stdin.resume()
});

const regex = new Map();

rl.on('line', l => {

  if (regex.size < 1) {
    process.stdout.write(l + '\n');
    return;
  }

  for (let [k, v] of regex) {
    if (v.test(l)) {
      process.stdout.write(chalk.magenta(' (filtered) ') + l + '\n');
      break;
    }
  }

});

interface IncomingTCPMessage {
  command: {
    add: string,
    remove: string,
    list: boolean,
    removeall: boolean
  }
}

const server = net.createServer(s => {

  const sendMessage = (m: any) => {
    s.write(JSON.stringify({message: m}) + `\n`);
  };

  s.pipe(createParser()).on('data', (d: IncomingTCPMessage) => {

    if (!d.command) {
      log.error('No "command" field was found:', d);
      return ''
    }

    const c = d.command;

    if (c.list) {
      sendMessage({regexes: Array.from(regex.keys()).map(k => ({regex: regex.get(k), str: k}))});
      log.info('Listing all regex for the client.');
      return;
    }

    if (c.removeall) {
      regex.clear();
      sendMessage(`Cleared all regex.`);
      log.info('Cleared all regex.');
      return;
    }

    if (c.add) {
      regex.set(c.add, new RegExp(c.add));
      sendMessage(`Added regex: ${c.add}.`);
      log.info('Added regex:', c.add);
      return;
    }

    if (c.remove) {
      regex.delete(c.remove);
      sendMessage(`Deleted regex: ${c.remove}.`);
      log.info('Removed regex:', c.remove);
      return;
    }

    log.error('No matching field was found:', d);
    log.info('Regex:', regex);

  });

});

server.listen(port);

to see the complete code, see:
https://github.com/ORESoftware/dygrep


---

