1

I need a tool that monitors output of other command, and when it prints specified string, eg. "error", stops monitored command. Then I modify some environment and files and continue job. Is it possible?

Edit: Example:

Have a following job.sh

for i in $(ls)
do
    echo file $i
    sleep 0.1
    cat $i
done

When run in folder containing files a.txt and b.txt, I want to pause job.sh after it print file b.txt for editing it, then continue job.sh and see new b.txt content. I can't touch job.sh as it is actually compiled C program. Sleep symbolizes that pausing do not have to be immediate, but still fast.

  • You can't modify the environment of the process you are monitoring. Are you instead intending to rerun the command? – Kusalananda Jul 13 '18 at 10:01
  • I do not mean shell environment variables, but files on disk. I do not want rerun. – Chocimier Jul 13 '18 at 10:04
2
% ./mystery
a
b
c
% 

One could issue the STOP signal to a program and then CONT to continue it; the following TCL code waits for b to appear in the output and at that point stops the process, which should remain stopped until the user types a line for expect_user to act on (at minimum a newline).

#!/usr/bin/env expect
spawn -noecho ./mystery
set spid [exp_pid]
expect -ex b { exec kill -STOP $spid; send_user "STOP\n" }
expect_user -re . { exec kill -CONT $spid }
expect eof

This of course has all sorts of problems, such as if mystery runs too quickly, or if the output is buffered, etc. I had to slow the C down and turn off buffering for it to work out:

% cat mystery.c
#include <stdio.h>
#include <unistd.h>
int main(void)
{
    setvbuf(stdout, (char *) NULL, _IONBF, (size_t) 0);
    printf("a\n");
    sleep(1);
    printf("b\n");
    sleep(1);
    printf("c\n");
    return 0;
}

A C program may be better controlled by running it under a debugger such as gdb; breakpoints would be a far more accurate way to halt the execution at an exact point in the code than reacting to I/O. Debugging symbols will help but are not necessary:

% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) quit
% otool -dtv mystery | grep callq
0000000100000f26        callq   0x100000f70
0000000100000f32        callq   0x100000f6a
0000000100000f3c        callq   0x100000f76
0000000100000f48        callq   0x100000f6a
0000000100000f52        callq   0x100000f76
0000000100000f5e        callq   0x100000f6a

So this is actually on a Mac (disassembly will vary by platform). The above are the setvbuf, printf, and sleep calls so with the start address

% otool -dtv mystery | sed 3q
mystery:
_main:
0000000100000f06        pushq   %rbp
% perl -E 'say 0x0000000100000f52 - 0x0000000100000f06'
76
% gdb mystery
Reading symbols from mystery...(no debugging symbols found)...done.
(gdb) b *main + 76
Breakpoint 1 at 0x100000f52
(gdb) r
Starting program: /Users/jhqdoe/tmp/mystery
a
b

Breakpoint 1, 0x0000000100000f52 in main ()
(gdb) 

And then you can do whatever is necessary and continue the program as desired.

Another idea would be to use LD_PRELOAD to adjust how the program behaves, assuming of course that the most sensible option—recompiling the program from source—is not possible. Yet another option would be to patch the C binary to behave as desired.

  • TCL solution works for me, thanks! As job is long-running, I added set timeout -1 after shebang. – Chocimier Jul 14 '18 at 7:39
0

You can use read which waits for user input before proceeding

Example:

This program runs a loop and prints output of ls -lhtr , waits for user input ( Press enter or any other character ) and then again prints output and continues the process in an infinite loop

#!/bin/bash

while (true); do
        ls -lhtr;
        read i;
done

So basically inlace of ls -lhtr , you can use the command whose output you need to monitor , once you are finished with modifying environment and files, you can press any key to continue monitoring the command output again

  • Here stopped command is a continously printing script. It was modified to be stopped. I want to stop command without modifying it. – Chocimier Jul 13 '18 at 10:19
  • @Chocimier you can call the continuously printing script from another script , so there will be no need of modifying the command. you are basically creating a wrapper over your existing script , e.g. replace ls -lhtr with bash test.sh – Arushix Jul 13 '18 at 10:27
  • I need to break single command, not loop. See added example in question. – Chocimier Jul 13 '18 at 10:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.