Python Scripting: How can I obtain the output from async_send_text?

35 views
Skip to first unread message

Eric G

unread,
Nov 27, 2024, 4:47:42 PM11/27/24
to iterm2-discuss
I can send a command to a session by doing:

await currentSession.async_send_text( 'ls\r' )

and I would like to obtain the output of that command. I thought I might be able to determine the position of the old prompt and the new prompt, but couldn't get that to work. I figure I may be able to get all of the output in the session via async_get_screen_contents and then start parsing to get what I am looking for.

What is the standard way of doing that?




George Nachman

unread,
Nov 29, 2024, 12:40:49 PM11/29/24
to iterm2-...@googlegroups.com
It’s a little more complex than I would like. Here’s how I would write it:

#!/usr/bin/env python3.10

import asyncio
import iterm2

async def wait_for_prompt(connection, my_session):
    """Block until the running command terminates."""
    modes = [iterm2.PromptMonitor.Mode.COMMAND_END]
    async with iterm2.PromptMonitor(connection, my_session.session_id, modes) as prompt_monitor:
        while True:
            type, value = await prompt_monitor.async_get()
            if type == iterm2.PromptMonitor.Mode.COMMAND_END:
                return

async def string_in_lines(my_session, start_y, end_y):
    """Returns a string with the content in a range of lines."""
    contents = await my_session.async_get_contents(start_y, end_y - start_y)
    result = ""
    for line in contents:
        result += line.string
        if line.hard_eol:
            result += "\n"
    return result

async def run_command(connection, my_session, command):
    """Run a command and return its output. Requires shell integration."""
    # Atomically get the last prompt, send a command, and begin watching for the end of the command.
    async with iterm2.Transaction(connection):
        prompt = await iterm2.async_get_last_prompt(connection, my_session.session_id)
        await my_session.async_send_text(command + "\r")
        task = asyncio.create_task(wait_for_prompt(connection, my_session))

    # Wait for the command to end.
    await task

    # Re-fetch the prompt for the command we sent to get the current output range.
    async with iterm2.Transaction(connection):
        prompt = await iterm2.async_get_prompt_by_id(connection, my_session.session_id, prompt.unique_id)
        range = prompt.output_range
        start_y = range.start.y
        end_y = range.end.y

        # Fetch the content in that range and return it
        content = await string_in_lines(my_session, start_y, end_y)
    return content

async def main(connection):
    """Demonstrate how to use run_command"""
    app = await iterm2.async_get_app(connection)
    if app.current_terminal_window:
        my_session = app.current_terminal_window.current_tab.current_session
        print(await run_command(connection, my_session, "seq 150"))

iterm2.run_until_complete(main)


--
You received this message because you are subscribed to the Google Groups "iterm2-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to iterm2-discus...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/iterm2-discuss/caea5a23-c63c-4a3a-990d-301c33e25602n%40googlegroups.com.
Message has been deleted
Message has been deleted

Eric Gorr

unread,
Nov 29, 2024, 4:07:32 PM11/29/24
to iterm2-...@googlegroups.com
Thank you for that. I would have been hard pressed to figure that out for myself.

It may be worthwhile adding a convenience function like async_send_text_with_output which returns the output from the command...



Eric Gorr

unread,
Jul 5, 2025, 2:48:20 PMJul 5
to iterm2-...@googlegroups.com
Based on behavior I am seeing, if there is already a prompt for the user to enter something, 

await prompt_monitor.async_get() 

will never terminate. So, is there a way for me to see if there is a prompt waiting? 

George Nachman

unread,
Jul 11, 2025, 3:01:15 PMJul 11
to iterm2-...@googlegroups.com
You can use async_get_last_prompt. Here is a REPl session where s is a Session object. 

Initially, we are at the command prompt:
>>> p = await iterm2.async_get_last_prompt(connection, s.session_id)
>>> p.state
<PromptState.EDITING: 0>

I run cat and do it again:
>>> p = await iterm2.async_get_last_prompt(connection, s.session_id)
>>> p.state
<PromptState.RUNNING: 1>


--
You received this message because you are subscribed to the Google Groups "iterm2-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to iterm2-discus...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages