L1lda
L1lda

Reputation: 3

Set timeout for command execution and output results to file

i have a basic script.sh that runs some commands inside. The script is like:

(script.sh)

......
`gcc -o program program.c` 
 if [ $? -eq 0 ]; then
    echo "Compiled successfully....\n" >> out.txt

 #set a timeout for ./program execution and append results to file
 (gtimeout 10s ./program) 2> out.txt  # <-- NOT WORKING

......

I run this script through the terminal like:

#Go to this directory,pass all folders to compile&execute the program.c file 
czar@MBP~$  for D in /Users/czar/Desktop/1/*; do sh script.sh $D; done

EDIT: The output i get in the terminal, not so important though:

# program.c from 1st folder inside the above path
Cycle l=1: 46 46
Cycle l=1: 48 48
Cycle l=2: 250 274 250
Cycle l=1: 896 896
.........
# program.c from 2nd folder inside the above path
Cycle l=1: 46 46
Cycle l=1: 48 48
Cycle l=2: 250 274 250
Cycle l=1: 896 896
.........

The GOAL is to have those into the out.txt

The output i get is almost what i want: it executes whatever possible in those 10seconds but doesn't redirect the result to out.txt, it just prints to the terminal. I have tried every suggestion proposed here but no luck.

Any other ideas appreciated.

EDIT 2: SOLUTION given in the comments.

Upvotes: 0

Views: 2695

Answers (1)

rici
rici

Reputation: 241711

The basic approach is much simpler than the command you copied from the answer to a completely different question. What you need to do is simply redirect standard output to your file:

# Use gtimeout on systems which rename standard Gnu utilities
timeout 10s ./program >> out.txt

However, that will probably not produce all of the output generated by the program if the program is killed by gtimeout, because the output is still sitting in a buffer inside the standard library. (There is nothing special about this buffer; it's just a block of memory malloc'd by the library functions the first time data is written to the stream.) When the program is terminated, its memory is returned to the operating system; nothing will even try to ensure that standard library buffers are flushed to their respective streams.

There are three buffering modes:

  • Block buffered: no output is produced until the stream's buffer is full. (Usually, the stream's buffer will be around 8kb, but it varies from system to system.)

  • Line buffered: output is produced when a newline character is sent to the stream. It's also produced if the buffer fills up, but it's rare for a single line to be long enough to fill a buffer.

  • Unbuffered: No buffering is performed at all. Every character is immediately sent to the output.

Normally, standard output is block buffered unless it is directed to a terminal, in which case it will be line buffered. (That's not guaranteed; the various standards allow quite a lot of latitude.) Line buffering is probably what you want, unless you're in the habit of writing programs which write partial lines. (The oddly-common idiom of putting a newline at the beginning of each output line rather than at the end is a really bad idea, precisely because it defeats line-buffering.) Unbuffered output is another possibility, but it's really slow if the program produces a substantial amount of output.

You can change the buffering mode before you write any data to the stream by calling setvbuf:

/* Line buffer stdout */    
setvbuf(stdout, NULL, _IOLBF, 0);

(See man setvbuf for more options.)

You can also tell the library to immediately send any buffered data by calling fflush:

fflush(stdout);

That's an effective technique if you don't want the (slight) overhead of line buffering, but you know when it is important to send data (typically, because the program is about to do some very long computation, or wait for some external event).

If you can't modify the source code, you can use the Gnu utility stdbuf to change the buffering mode before starting the program. stdbuf will not work with all programs -- for example, it won't have any effect if the program does call setvbuf -- but it is usually effective. For example, to line buffer stdout, you could do this:

timeout 10s stdbuf -oL ./program >> out.txt
# Or: gtimeout 10s gstdbuf -oL ./program >> out.txt

See man stdbuf for more information.

Upvotes: 1

Related Questions