How do I launch an editor from a shell script? - vim

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?

I answered my own question! You have to redirect terminal input and output:
#!/bin/tcsh
vi my_file < `tty` > `tty`

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.

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

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.

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.

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

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.

Related

How to redirect vim's output to terminal?

I'm currently writing a small bash script to create a pre-filled file at a specific location. To do so, my bash script call vim and execute a vim script.
In this vim script, I want to ask to the user if the location where the created file is going to be saved is the correct one. The user then enter yes or no.
To do so, I'm using this set of command:
call inputsave()
let name = input('Is it the correct location ? y/n')
call inputrestore()
this input function works fine when I'm in gvim or vim. But from a script, nothing is displayed is the terminal where I launched my bash script.
Is there a way to redirect outputs to my terminal ?
I found :redir > {file} but this is obviously redirecting all vim outputs to a file which not interactive.
I also managed to echo something int the terminal by using this:
let tmp = "!echo what I want to display"
execute tmp
unlet tmp
but again this is only to display something. I won't be able to enter an input
my bash script:
#!/bin/bash
touch tmp.txt #file used to pass argument to vim
echo "$1" >> tmp.txt #append argument to the end of the txt file
vim -e tmp.txt <create_new_file.vim #launch vim and execute the scrip inside create_new_file.vim
rm tmp.txt
echo "new file created"
the create_new_file.vim basically just call my function CreateFile(_name) located in my .vimrc. This is this function who call inputsave(), input() and inputrestore().
You're feeding commands directly into Vim via standard input; this way, Vim has no way to interact with you (the user), and this use of Vim is atypical and therefore discouraged.
Alternatives
Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.
That said, you can use Vim non-interactively:
Full Automation
For more advanced processing involving multiple windows, and real automation of Vim (where you might interact with the user or leave Vim running to let the user take over), use:
vim -N -u NONE -n -c "set nomore" -S "create_new_file.vim" tmp.txt
This should allow you to interact with Vim while following a script of commands.
Here's a summary of the used (or useful) arguments:
-N -u NONE Do not load vimrc and plugins, alternatively:
--noplugin Do not load plugins.
-n No swapfile.
-i NONE Ignore the |viminfo| file (to avoid disturbing the
user's settings).
-es Ex mode + silent batch mode -s-ex
Attention: Must be given in that order!
-S ... Source script.
-c 'set nomore' Suppress the more-prompt when the screen is filled
with messages or output to avoid blocking.

Cygwin terminal input disappearing after quitting vim

Using Cygwin, I tried creating and editing a file in Vim:
touch test | vim
This is obviously a mistake; something like vim "$(touch test)" has a better chance of actually working. Nevertheless, this command throws the error:
Vim: Warning: Input is not from a terminal.
And after this, Vim opens and I exit the program with :q. Any subsequent commands I enter into the terminal are hidden from view until I restart Cygwin.
Why is this?
You don't understand what does a pipe | do in shell.
Pipe will take the pervious command's stdout as stdin to next command, in a subshell.
Your touch foo doesn't generate any output, what do you expect to happen? same for vim "$(touch test)".
If you want to create a file and open it in vim in one shot, you can try:
touch foo && vim foo
If you want to edit it with vim anyway, actually, you can simply just:
vim foo
then save the buffer after your editing.

store all the data in terminal to text file by tee command or equivalent tool

I learnt that a tee command will store the STDOUT to a file as well as outputs to terminal.
But, here the problem is every time I have to give tee command, for every command I give.
Is there any way or tool in linux, so that what ever I run in terminal, it should store the command as well as output. (I used tee command in MySQL, where it will store all the commands and outputs to a file of that entire session. I am expecting a tool similar to this.)
Edit:
When I run script -a log.txt, I see ^M characters as well as ^[ and ^] characters in log.txt file. I used various dos2unix, :set ff=unix, :set ff=dos commands, but they didn't helped me in removing these ^[, ^] characters.
Is there any method, I can directly get the plain text file (with out these extra chars).
OS: RHEL 5
You can use script command which writes everything on file
script -f log.txt
you could use aliases like such alias ls="ls;echo ls >>log" so every time you run ls it runs echo ls >>log too.
But script would probably be better in this case, just dont go into vi while you are in script.

Run a shell command through Perl in a specific terminal

First off, I am pretty new to Perl so I may be missing something obvious. This is not the typical "I want to run a shell command through Perl" question.
I don't want to capture all of the shell output. I have a program/script that intelligently writes to the terminal. I didn't write it and don't know how it all works, but it seems to move the view to the appropriate place after printing some initialization, then erase previous terminal output and write over it (updates) until it finally completes. I would like to call this from my perl script rather than printing everything to a file to grab it after, since printing to a file does not keep the intelligence of the printout.
All I need to do is:
open an xterm in my perl script
make a system call in that terminal
have that terminal stay up until I manually exit it
Can I do this in perl?
Thanks.
system 'xterm', '-hold', '-e', $program;
where $program is the terminal-aware program you want to run.
-hold causes xterm to stay open after the program exits, waiting for you to close it manually.
-e specifies the program or command line to run. It and its argument must appear last on the xterm command line.
Try doing this by example :
#!/usr/bin/env perl
use strict; use warnings;
use autodie;
open my $term, '| xterm -hold -e $(</dev/stdin)';
foreach my $dir (qw|/etc /usr /home|) {
print $term "ls $dir\n"; # do anything else you'd like than "ls $dir" here
}
close $term;

Why does "locate filename | xargs vim" cause strange terminal behaviour?

When I do "locate 50local.policy | xargs vim", I get the error "Vim: Warnung: Die Eingabe kommt nicht von einem Terminal" (translation: Vim: Warning: The input does not come from a terminal).
I can edit successfully with vim but after I close it my terminal behaves strangely (I can't type letters and when I hit enter the shell prompt simply gets repeated.
When I do it with "xargs gedit" it does not create those problems.
I use Ubuntu 11.10 with Gnome 3 and Gnome-Terminal 3.0.1.
Vim expects to be connected to a real terminal and sends codes appropriate to that.
Reset the terminal with
reset
The easiest workaround:
locate 50local.policy | xargs gvim
Rationale gui vim doesn't require a terminal
Otherwise:
vim $(locate 50local.policy)
Rationale vim is started directly connected to the terminal (instead of as a child process under xargs which in turn runs in a subshell with stdin/stdout connected to pipes instead of a terminal). It is like saying
vim /usr/some/dir/50local.policy /usr/local/some/dir/50local.policy
Alternatively
You can dodge the issue by not starting vim with the arguments, but adding the arguments from vim! Vim is in fact a lot better at running shells than shells are at running vim.
Whilst in vim:
:args `locate 50local.policy`
:rewind
This sets the argument list to the files returned from the shell command between the ticks; :rewind then goes to the first file from that list.
If you were editing multiple matches, try this:
:w|next
This sequence of commands (separated by |) writes the current buffer to file, then goes to the next file in the args list.
An other alternative is to execute xargs with the -o option. From the man page:
-o Reopen stdin as /dev/tty in the child process before executing
the command. This is useful if you want xargs to run an interac-
tive application.
Note, -o is a BSD extension to xargs.
A more portable means to achieve the same effect is:
xargs sh -c 'vim "$#" < /dev/tty' vim
While 'reset' fixes the problem, you can also explicitely re-activate the echo behaviour with:
stty echo

Resources