How do I selectively kill an "execute shell script" action?

I run this continuously:

But whenever I clear out TWServerLog.log, the tail stops working for some reason and I have to restart this action i.e. the whole macro. Since there is no way to selectively cancel a macro, I've been trying to find out how I can kill the while loop.

So I want to get the PID back to KM and just kill it.


done &
set thePID %1


But in all my attempts to get $thePID back to KM with osascript, for some reason none of them are working. I've narrowed it down to the fact that KM shell scripts seem to have some disability when it comes to passing variables around. The following command works correctly in terminal but displays an empty alert as an execute text script action:

tail -f /Users/Matt/Documents/Logs/TWServerLog.log &\
         set thePID %1
         osascript -e 'on run argv
         display alert (do shell script "echo '$thePID'")
         end run'`

I've learned recently that KM shell actions need to always call commands according to their exact location. So for example, tag -Atf \* had to become /usr/local/bin/tag -Atf \*. Is there something special we have to do for variables as well?

You can selectively cancel macros in the Cancel sub-macro in the status menu.

When you rotate the log, the tail remains tailing the old file (which no longer changes) while the new file gets the new data, hence the tail and script stop producing information.

A neat solution would be to write a line to the log with “Rotating” and have your script detect that and break from the loop and perhaps pause a short time and then restarting the tail.

You can write a Keyboard Maestro variable as described at:

And the debug menu. Of course, I meant automatically.

I’m not sure if what I’m doing is technically rotating. When the file sure becomes over 1mb, I just write a line to it instead of appending and delete all the old text. Perhaps tail just doesn’t move back to the beginning.

Of course… why didn’t I think of that! :sweat_smile:

No. You have to have a deeper understanding of how unix works to fully understand it, but the basic concept is that the name of a file is really just a pointer to the data. You can have two differently named files linking to the same data (this happens if you make a hard link). Deleting a file removes the name and the link to the data, but the data is only freed when the last link to it is deleted.

Opening a file (like tail -f does) also links to the data. So when you delete the file and create a new one (as writing a line to it does), you erase the original file link, but the open link that tail have remains valid, as does the data on the disk. Until such time as tail closes the file (eg by you killing the script).

Actually, I suppose if the script is always running, you could just write the “Rotating” line to the file and let the script recreate the file and that would avoid the race condition of waiting in the script for the new file to happen.

1 Like

Very interesting, and I will definitely try to implement your ideas. There is one problem though, and that’s the cpu usage. I noticed that KM jumps up about 18% in cpu usage just from trying this single action (unaltered as of now from my first image), while doing the same exact thing in terminal runs completely silent at 0.0% cpu. Any suggestions?

Yes, Keyboard Maestro Engine CPU usage is very low if it is not running any macros.

As soon as it is running a macro its CPU usage will increase. I do make every effort to minimize CPU usage when no macro is running, and while I don’t go out of my way to make CPU usage bad, I don’t go out of my way to minimize CPU usage while a macro is running.

Note that since you don’t care about the output, you can configure the Execute Shell Script to execute asynchronously, which means the macro will complete but the script will keep running. In that case, you’ll have no way to cancel it, but Keyboard Maestro Engine will not wait for the script to finish and so will not use any CPU for it.

But if you want this script running permanently, then you would be better off creating a Launch Daemon for it. I use Lingon X for managing launch daemons.

1 Like