Extending the last output script
November 26, 2011 at 10:57 PM by Dr. Drang
As threatened at the end of my last post, I’ve extended the script for putting the output of the last command in Terminal to handle Octave and Python sessions as well as bash sessions. I often need to include results from these sessions in reports and other documents, and a quick keyboard command is faster and more accurate than clicking and dragging, especially when I’m working on my MacBook Air and using a trackpad.
Like the simpler script that handled bash only, the extended version does the following:
- Splits the
history
of the current Terminal tab on the command prompt. - Grabs the item that contains both the input and output of the last command.
- Eliminates the input.
- Puts the result on the clipboard.
To handle Python and Octave in addition to bash, the script needs to know which interpreter is running and the prompt that interpreter uses.
On my system, the titlebar of the Terminal window displays, among other things, the name of the program being executed. This is set by checking the “Active process name” item in the Window settings.
A quick look through the AppleScript dictionary for Terminal shows that the name
property of a window
contains the window’s title. We’ll use that to check for “octave,” “python,” or “bash.”
As for the prompts, we have to be careful because both Python and Octave have two types of input prompts: the primary prompt and the secondary (or continuation) prompt. Commands always start after the primary prompt. If the command extends over more than one line—as with loops and branches—the second and later lines are entered after the secondary prompt. Here’s an example from an interactive Python session:
>>> for i in range(1,6):
... square.append(i**2)
... cube.append(i**3)
By default, Python’s primary and secondary prompts are >>>
and ...
, respectively, each with a trailing space. As you’ll see in the script source code, to get just the output I split first on the primary prompt and then on the secondary.
Octave’s default primary prompt includes the word “octave” and the command number, which starts with 1 at the beginning of the Octave session. This is unnecessarily long and includes information of little value to me. In several years of using Octave, I’ve never once used the command number. I like Python’s prompts because the primary and secondary are the same length, which makes it easy to use conventional indentation in an interactive session, so I’ve changed Octave’s prompts to match Python’s. Adding these lines to my ~/.octaverc
file makes the changes.
PS1(">>> ")
PS2("... ")
With that in mind, here’s the revised code for “Copy Last Output:”
python:
1: #!/usr/bin/python
2:
3: from appscript import *
4: from osax import OSAX
5:
6: sa = OSAX()
7: win = app('/Applications/Utilities/Terminal').windows[1]
8: title = win.name.get().lower()
9:
10: if title.find("bash") > -1:
11: inout = win.selected_tab.history.get().split('\n$ ')[-2]
12: sa.set_the_clipboard_to('\n'.join(inout.split('\n')[1:-1]))
13: elif title.find("python") > -1 or title.find("octave") > -1:
14: inout = win.selected_tab.history.get().split('\n>>> ')[-2]
15: sa.set_the_clipboard_to('\n'.join(inout.split('\n... ')[-1].split('\n')[1:]))
If you want to use this or modify it for your own purposes, you’ll have to have the appscript
library installed.
Line 8 gets the title of the current window, and the if/elif
structure tests for which interpreter is running. Octave and Python are handled by the same code because I have them set to use the same prompts.
This has replaced my earlier, simpler script. I have FastScripts set up to run this command when Terminal is the active application and I press ⌃⌥⌘C.