views:

325

answers:

5

I would like my tcsh script to launch an editor (e.g., vi, emacs):

#!/bin/tcsh
vi my_file

This starts up vi with my_file but first displays a warning "Vim: Warning: Output is not to a terminal" and my keystrokes don't appear on the screen. After I kill vi, my terminal window is messed up (no newlines), requiring a "reset". I tried "emacs -nw", "xemacs -nw", and pico with similar results. "xemacs" works but launches a separate window. I want to reuse the same terminal window.

Is there a way to launch an editor from a script so that it reuses the same terminal window?

+1  A: 

I answered my own question! You have to redirect terminal input and output:

#!/bin/tcsh
vi my_file < `tty` > `tty`
Marc Eaddy
but... but... but... redirect from where? It's still a mystery to me why you should need to do this.
Carl Smotricz
A: 

I was able to get the desired behavior under bash+Cygwin+Terminator:

#!/bin/bash
vim foo

Run the script, vim loads, no error messages, behaves as normal. There are undoubtedly dozens of variations between our setups, however, so I can't hazard a guess as to what makes the difference. I'm curious what it is, but you got it working, which is the important part.

qid
+2  A: 

The reason you're getting the error is that when you start a shell in your environment, it's starting in a subshell that has STDIN and STDOUT not connected to a TTY — probably because this is in something like a pipeline. When you redirect, you're opening a new connection directly to the device. So, for example, your command line turns

$ vi < `tty` > `tty`

into

$ vi < /dev/ttys000 > /dev/ttys000

So you're not really using your old STDIN/STDOUT, you're creating two new files and mapping them to your vi process's STDIN/STDOUT.

Now, tell us what you're doing with this and we'll tell you how to avoid this kludge.

Charlie Martin
I'm not creating new files. I'm redirecting my terminal device file (tty tells you which file it is), which is associated with my terminal window and existed prior to running my script, to the STDIN/STDOUT of vi.I created a script that wraps "cvs commit" and does a lot of extra checks (e.g., runs our test suite) before committing a check-in. This is sometimes called a "gated checkin." For reasons I won't go into, I can't use the standard CVS pre-commit hook. I'm trying to emulate how "cvs commit" launches an editor when you don't specify a commit message on the command line.
Marc Eaddy
+1  A: 

Absolutely. :-)

Write your script and have it call the EDITOR environment variable, which you will have set to "emacsclient". Then start up Emacs, execute M-x server-start, switch to a shell buffer (M-x shell) and execute your script. Emacsclient will pop up the thing to be edited and C-x # will act as a "done" command and take you back to your script with edits completed or aborted, as you choose.

Enjoy.

Edit: I meant to add that these days Emacs IS my terminal program. I have dozens of shell buffers and never have to worry about losing output and can use all the power of Emacs to manipulate and analyse the terminal output. And have Emacs scripts generate input to the shells. Awesome actually. For example, watching Tomcat output scroll by in a shell buffer while editing sources or processing mail or doing most any Emacs thing is very convenient. When a Tomcat stack trace appears I can quickly respond to it.

pajato0
A: 

Set your terminal tty to a variable, and then redirect the editor i/o through that variable.

In your script:

#!/bin/sh

ls | while read a; do vi $a < $MYTTY >$MYTTY; done

And then execute the script with:

MYTTY=`tty` ./myscript >/tmp/log

Sami