How do I launch an editor from a shell script?

2020-05-23 02:26发布

问题:

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:

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

#!/bin/tcsh
vi my_file < `tty` > `tty`


回答2:

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.



回答3:

I wanted to do something similar. I wanted an alias that would find the last file I was working on, and open it in vi(1) for editing. Anyway, I couldn't figure out how to do it as a readable alias (in tcsh) so I just created an ugly shell script (csh because I'm old) instead:

#!/bin/csh

set DIR = "~/www/TooMuchRock/shows/"

set file = $DIR`ls -t $DIR | head -1`
set tty = `tty`

vi $file <$tty >$tty

(1) kraftwerk:bin> which vi vi: aliased to /usr/local/bin/vim -u ~/.exrc



回答4:

Had the same trouble with 'pinfo' in a shell script 'while' loop. The line can be used in the script, it uses 'ps' to find the tty of the current process number, "$$", and stores that tty in $KEY_TTY:

  KEY_TTY=/dev/`ps | grep $$ | tr -s '[:blank:]' | cut -d " " -f 3`

Later in the script, just call the tty-only proggie, with $KEY_TTY as input, in my case it was:

  pinfo -m $s $page < $KEY_TTY

For 'vi' it'd be:

  vi $a < $KEY_TTY > $KEY_TTY

The advantage is that the script as a whole can still accept STDIN input, and 'vi' (or whatever) should work fine -- without having to remember to set any environmental variables before running the script.



回答5:

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


回答6:

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.



回答7:

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.