unix pipe in AppleScript

Dear all,

Recently we spent a few days in figuring out the best way for doing a unix pipe through AppleScript. We have found a way that works quite well (by creating a temporary file which acts like a pipe), but we still have a few problems killing the processes we have spawned.

First we tail a temporary file into a gnuplot. We are using the bash-terminal for ensuring compatability with the Terminal. This creates three processes: bash, tail and gnuplot.


do shell script "bash -c \"tail -f /tmp/output1 | gnuplot\" &> /dev/null & echo $!"

The resulting PID we get as a result of this line is the one of the bash-shell. However when we kill this process at a later stage, through the statement below, only the bash-process gets killed and the two other processes keep on running.


do shell script "kill pid_returned_by_previous_line"

For your information, we are writing some research tools in Lisp (Macintosh Common Lisp) and we need some way to create unix pipes for plotting graphs in gnuplot.

Also note that we’d like to show several graphs at the same time which limits our options (for instance we can’t kill processes using their names).

Thanks for any insights we get by your feedback,

Joris

When I want monitorize or run complex command-line things, I allways use this method:
-Write the bash/perl/whatever script to a temporary file. Chmod it.
-Execute from AppleScript without waiting for results.
-Monitorize.

Eg:

set ss to "#! /bin/bash" & (ASCII character 10) & ¬
	"openssl md5 '/path/to/long_file.dmg' &> /dev/null & echo $! > /tmp/openssl_1_PID;"

--> write to tmp file
set f to (open for access ("/tmp/tmpfile" as POSIX file) with write permission)
set eof of f to 0
write ss to f
close access f

--> chmod+execute ignoring result
do shell script "cd /tmp; chmod 755 tmpfile; ./tmpfile > /dev/null 2>&1 &"

--> monitorize (basic sample)
repeat
	--> get PIDs of running "openssl" threads. Eg:
	set PIDs to paragraphs of (do shell script "ps -cax | grep -i openssl | awk '{print $1}'")
	--> check against PIDs found in /tmp dir, called "openssl_1_PID", "openssl_2_PID", ...
	--> so, before you should track what processes you launched
	--> etc
	delay 1
end repeat

Hello JJ,

Thanks for your reply, it is very inspiring.

Translating your script in what we want to do resulted in:


set ss to "#!/bin/bash" & (ASCII character 10) & ¬
	"tail -F /tmp/output1 | gnuplot &> /dev/null & echo $! > /tmp/output1.pid;"

set f to (open for access ("/tmp/output1script" as POSIX file) with write permission)
set eof of f to 0
write ss to f
close access f

do shell script "cd /tmp; chmod 755 output1script; ./output1script &> /dev/null & echo $!"

The contents of /tmp/output1.pid now contains the PID of the gnuplot-process. We are one step closer, but not completely home, as we would want the PID of the tail-process.

I also tried to do this without the external script file using:


do shell script "bash -c \"tail -f /tmp/output1 | gnuplot &> /dev/null & echo $! > /tmp/output1.pid\" &> /dev/null &"

However, the contents of /tmp/output1.pid is empty now. To me it is still a mystery why this is true.

We’d also like to point a few things, as our goal might not have been as clear as we wished.

First, we don’t want to (unless this is necesarry for the goals we wish to achieve) to monitor the processes themselves, but results from simulations run in Lisp. For this purpose we want to run several gnuplot processes, one for each graph.

Second, it needs to be two seperate AppleScripts: at the beginning of an experiment we open the ‘pipe’ (using AppleScript through Lisp), during the experiment we send information to that ‘pipe’ (using Lisp), at the end of an experiment we close the ‘pipe’ (using Applescript through Lisp).

Third, we need to be able to identify the processes for each monitor. During the experiment new monitors might be needed or might be deleted.

Fourth, if it is easier to do without the compatability of the bash-shell, we are willing to give up on it.

Kind regards,

Joris

Well, I’ve already shown all my knowledge about *nix scripting, so I can only offer more AS-stuff.
It won’t be easy nor clear nor a shortcut, but should work: do not use pipes.
-Invoke “tail” and pass the output to a temporary file (instead of pipe-ing it to gnuplot).
-Monitorize “tail” by PID.
-When it’s done (it isn’t in the “ps” list), call gnuplot providing as input such temporary file.
-Monitorize it by PID.

This way, you can keep full control over the process and kill whatever you want at any moment.

If you need accessing this data (list of PIDs and status of “queue”) from several scripts, simply write it to external files (eg, a temporary text file or entries in a plist file using the “defaults” command-line tool).

Will be the long way, but seems an ambitious project :stuck_out_tongue:

Hi JJ,

I don’t think I understand you completely. We want to have a stream of data for each gnuplot-process which might be running over a longer period of time. I don’t understand how this is possible without using a pipe.

  1. Invoke tail and pass the output of it to a temporary file. When it’s done …

I don’t see how this might be, “tail -f …” doesn’t return (unless you put it in the background). I also don’t see how this might help as we already have a file to which is written constantly through Lisp.

  1. Call gnuplot providing as input the temporary file

Calling “gnuplot” without a pipe creates an new instance of gnuplot, but we want to be able to use the same gnuplot-process and keep streaming data to it.

By the way: if your previous code should be programmed in AppleScript can you provide the code for it? Our knowledge of AppleScript is quite slim.

And indeed, it is an ambitious project we are working on!

Joris

Well, I don’t know at all how does it work Lisp nor gnuplot, so I’m not sure I can help far from what I already said :confused: