0

I am using Python to execute an external program by simply using Python's "os" library:

os.system("./script1") # script1 generates several log files and the most important for me is "info.log" !
os.system("./script2") # script2 uses the output from script1

The problem is that those scripts are in 50000 element "for loop" and "script1" needs at least 2 min to finish its job (it has fixed time duration) In the first 1-2 sec I can find out whether I need the output data or not by looking in to the "info.log" file. However, as "script1" is an already compiled program and I can't modify it, I have to wait until it finishes.

I was thinking about a method in Bash that allows me to run two processes at the same time: one is to start ./script1 and the other is to monitor any change in the "info.log" file...
If "info.log" has been updated or changed in size, then the second script should terminate both processes.

Something like:

os.system("./mercury6 1 > ./energy.log 2>/dev/null & sleep 2 & if [ $(stat -c %s ./info.log) -ge 1371]; then kill %1; else echo 'OK'; fi")

– which does not work...

Please, if someone knows a method, let me know!

Oleh Prypin
  • 33,184
  • 10
  • 89
  • 99

5 Answers5

0
import os
import time

os.system("script1")

while True: # Now this would run in 10 sec cycles and checks the output of the logs
   try:     # And you don't have the wait the whole 2 mins to script1 to be ready
       o = open("info.log", "r") # or add os.system("script2") here
       # Add here more logs
       break
   except:
       print "waiting script1 to be ready.."
       time.sleep(10) # Modify (seconds) to be sufficient to script1 to be ready
       continue
jester112358
  • 465
  • 3
  • 17
0

I would suggest using subprocess, with a combination of this answer describing how to kill a bash script along with some method of monitoring the file, something like watchdog, or a simple polling loop.

Community
  • 1
  • 1
Henry Gomersall
  • 8,434
  • 3
  • 31
  • 54
0

You can try this one. Tell me if script1 pauses on runtime so we could try to configure it further.

#!/bin/bash

[ -n "$BASH_VERSION" ] || {
    echo "You need Bash to run this script."
    exit 1
}

set +o monitor ## Disable job control.

INFO_LOG='./info.log'

if [[ ! -f $INFO_LOG ]]; then
    # We must create the file.
    : > "$INFO_LOG" || {
        echo "Unable to create $INFO_LOG."
        exit 1
    }
fi

read FIRSTTIMESTAMP < <(stat -c '%s' "$INFO_LOG") && [[ $FIRSTTIMESTAMP == +([[:digit:]]) ]] || {
    echo "Unable to get stat of $INFO_LOG."
    exit 1
}

# Run the first process with the script.

./script1 &
SCRIPT1_PID=$!
disown "$SCRIPT1_PID"

# Run the second process.

(
    function kill_processes {
        echo "Killing both processes."
        kill "$SCRIPT1_PID"
        exit 1
    }

    [[ -f $INFO_LOG ]] || {
        echo "File has been deleted."
        kill_processes
    }

    read NEWTIMESTAMP < <(stat -c '%s' "$INFO_LOG") && [[ $NEWTIMESTAMP == +([[:digit:]]) ]] || {
        echo "Unable to get new timestamp of $INFO_LOG."
        kill_processes
    }

    [[ NEWTIMESTAMP -ne FIRSTTIMESTAMP ]] || {
        echo "$INFO_LOG has changed."
        kill_processes
    }

    sleep 4s
) &

disown "$!"

You might also want to check some other similar solutions here: linux script with netcat stops working after x hours


(
    function kill_processes {
        echo "Killing both processes."
        kill "$mercury6_PID"
        exit 1
    }
    while IFS= read -r LINE; do
        [[ "${LINE}" == "ejected" ]] && {  ## Perhaps it should be == *ejected* ?
            echo "$INFO_LOG has changed."
            kill_processes
        }
    done < <(tail -f "$INFO_LOG")
) &

disown "$!"
Community
  • 1
  • 1
konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • :) Thanks! I think this will work!!! however there is a little complication.. it turn out that the file is changing one time before the mercury script to start giving information.... ./monitor_mercury: line 58: disown: 0: no such job Integrating massive bodies and particles up to the same epoch. Beginning the main integration. - here after this line is important or can we make it to read the file and if there is string "AINNER" or "BOUTER" to stop the script? – Trifon Trifonov Aug 14 '13 at 09:57
  • About `disown 0`, the problem actually was because I used `$?`. It should have been `$!`: `disown "$!"`. I made the correction. We can perhaps but only if the file is not locked from read access while script1 is running. Can you check if it's still readable? So we actually wouldn't base from the file's timestamp anymore and just the strings? You can however wait for some seconds to let the mercury script for a while and start recording timestamps after that. – konsolebox Aug 14 '13 at 10:07
  • it is not locked! I frequently open this log when I start long calculations. – Trifon Trifonov Aug 14 '13 at 10:36
  • Also when define INFO_LOG='./info.log' the "info.log" does not exist and you create such. This is a problem because the mercury script terminates when tries to create the real "info.log"... It says ERROR: This file already exists: info.out – Trifon Trifonov Aug 14 '13 at 10:52
  • 1
    I have made one attempt: #!/bin/bash [ -n "$BASH_VERSION" ] || { echo "" exit 1 } set +o monitor INFO_LOG='./info.out' # Run the first process with the script. ./mercury6 & mercury6_PID=$! disown "$mercury6_PID" ( function kill_processes { echo "Killing both processes." kill "$mercury6_PID" exit 1 } tail -f $INFO_LOG | while read LINE do [[ "${LINE}" == *"ejected"* ]] && { echo "$INFO_LOG has changed." kill_processes } done ) & disown "$!" BUT! it stay on the line "Killing both processes." and doesn’t want to go further. – Trifon Trifonov Aug 14 '13 at 12:10
  • @user2681566 I'm not sure what commands you placed after the loop but using process substitution might help. Using pipe | places the command after it on another subshell so exit would only exit the subshell. Good idea bout using `tail -f` btw. I tried some solutions but it just closes reading on the end awhen EOF is reached. And using `sed -ne "${NEXTLINE}p"` was not a good idea. I posted the update about it btw. – konsolebox Aug 14 '13 at 13:00
  • Thanks again! This however works like the previouse :( (sorry but I am new and I cant post within 8h so my code looks terrible on the comment box) Here is the output: " Date: 7684... ./info.out has changed. Killing both processes." and nothing after that.... Do you think we have to kill "tile" to go out? of maybe the while loop is making problems... I have no idea but i know with your help I am getting closer to the solution. – Trifon Trifonov Aug 14 '13 at 13:18
  • Do you expect more messages after the kill is executed? Like from mercury or from the monitoring process? Or is mercury still running? Or is the monitoring process till running? You can add echo statements around the code to check if something is still happening, and perhaps to know also if you're really having the right process. You could also echo the values of the variables. Just add a note before the value like. `echo "Process ID of mercury: $mercury6_PID."`; `echo "Found line: $LINE."` – konsolebox Aug 14 '13 at 13:33
0

It has been done ! not so elegant but it works! this is the code:

#!/bin/bash

[ -n "$BASH_VERSION" ] || { echo "You need Bash to run this script." exit 1 }

# set +o monitor ## Disable job control.

INFO_LOG="./info.out"

# Run the first process with the script.

./mercury6 1 > ./energy.log 2>/dev/null & mercury6_PID=$! disown "$mercury6_PID"

# Run the second process.

( sleep 5 function kill_processes { echo "Killing both processes." kill "$mercury6_PID" exit 1 } while IFS= read -r LINE; do
[[ "${LINE}" == "ejected" ]] || [[ "${LINE}" == "complete." ]] && { echo "$INFO_LOG has changed." killall tail kill_processes } done < <(tail -f "$INFO_LOG") )

#&

#disown "$!"

If you have any recommendations you are very welcome! BTW I will try to make it with os.fork() in python as well. Thanks again!

-1

See here (Google is your friend). You can make the processes background tasks with the & sign, then use wait to have the parent process wait for its children.

kutschkem
  • 7,826
  • 3
  • 21
  • 56