Closed amosbird closed 5 months ago
kitten @ launch --type=background sh -c "stdout_and_stderr=$(some_script 2>&1)
kitten @ launch --type=background sh -c "stdout_and_stderr=$(some_script 2>&1)
It seems I didn't describe the FR clearly. I'd like to have the stdout/stderr redirects to the tty which executes the kitten command. For instance:
Current behavior:
$ kitten @ launch --type=background echo hello world
0 <--- currently it prints the exit status zero
Expected behavior:
$ kitten @ launch --type=background echo hello world
hello world <--- I'd like to get the stdout here
Run
echo hello world &
echo hello world &
Sorry I don't quite follow. How does this help?
It runs echo hello world in the background with its stdout/stderr connected to the tty.
The echo hello world
is just a demo script used to describe the FR. Real scripts will be only available on host machine and the kitten command will run on remote machine.
If you had said so in the first place, it would have saved some time.
Run:
kitten @ launch --type=background sh -c "exec whatever > /tmp/output 2> /tmp/output" && kitten transfer --direction=upload /tmp/output temp-output-file && cat temp-output-file && rm temp-output-file
You will get a permission prompt from the transfer kitten, read its docs to see how to avoid that.
Sorry for wasting your time. I'll do more preparation before submit FR next time :)
While the provided solution addresses certain scenarios, it falls short in cases where synchronization is necessary. I understand that additional "hacks," such as waiting for temporary result files to appear in the remote shell, can be implemented. However, wouldn't it be more straightforward to extend rc.Launch.response_from_kitty
with is_asynchronous = True
and utilize subprocess.Popen.communicate()
to wait for the output? I did some tests, and it seems working.
You are most welcome to send a PR to add that functionality, but note that to be acceptable it has to:
1) Allow sending stdin from the kitten invocation as stdin to the background process. See @ send-text for an example of how to implement this. You can possibly make it simpler to implement by only doing it when stdin is not a tty.
2) Return the stdout, stderr and exit status in the response which the kitten should then forward to its stdout, stderr and exit status.
Also note that you cannot use subprocess.communicate() as that will block the main thread of kitty. Instead you need to run the background process redirecting the output to unnamed temp files and in your response read from them. There is also the question of what to do when there is a lot of output, I dont recall if the kitten is able to read arbitrary sized responses from kitty, you will need to test.
Also, in the --no-response case it should work as it does currently, with no response.
Oh and just for completeness, your synchronized usecase can be implemented like this:
kitten @ launch --no-response --type=background --allow-remote-control sh -c "echo -e 'hello\nworld\nEOF' | kitten @ send-text --stdin --match id:$KITTY_WINDOW_ID"; stty_orig=`stty -g`; stty raw -echo; python -c "import sys; [sys.exit(0) if line.rstrip() == 'EOF' else print(line, end='\r') for line in sys.stdin]"; stty "$stty_orig"
In production you should of course use something more unique than EOF to signify end of input.
And because I'm on a roll, here's a version without EOF and stty
kitten @ launch --no-response --type=background --allow-remote-control sh -c "echo -e 'hello\nworld\nagain' | kitten @ send-text --stdin --match id:$KITTY_WINDOW_ID; kitten @ signal-child --match id:$KITTY_WINDOW_ID"; python -c "import sys, signal, os, tty, termios; attr=termios.tcgetattr(1); tty.setraw(1); signal.signal(signal.SIGINT, lambda *a: (termios.tcsetattr(1, termios.TCSANOW, attr), os._exit(0))); [print(line, end='\r') for line in sys.stdin]";
This should be completely robust and synchronous. It will even stream data from your command to STDOUT, not reading everything in a batch. Which your proposed changes to --type=background wont do.
You can make it not line buffered by replacing the python one-liner with a proper script that reads from stdin in non-blocking mode and writes to stdout, replacing all newlines by \n\r.
kitten @ launch --no-response --type=background --allow-remote-control sh -c "echo -e 'hello\nworld\nagain' | kitten @ send-text --stdin --match id:$KITTY_WINDOW_ID; kitten @ signal-child --match id:$KITTY_WINDOW_ID"; python -c "import sys, signal, os, tty, termios; attr=termios.tcgetattr(1); tty.setraw(1); signal.signal(signal.SIGINT, lambda *a: (termios.tcsetattr(1, termios.TCSANOW, attr), os._exit(0))); [print(line, end='\r') for line in sys.stdin]";
Interesting. But this doesn't work when kitten
is running inside an ssh session. Signaling ssh will directly kill the connection instead of passing it to the underlying foreground process.
Then use a terminator like EOF.
When executing
kitten @ launch --type=background some_script
, the stdout and stderr ofsome_script
are currently directed to the running terminal of kitty, with only the exit status being returned to the calling location.I am seeking an option to redirect the stdout and stderr back to the calling location. This helps implement workflows in remote that interact with the local host machine.