SIGWINCH, bash, dash, tput, and terminfo - ncurses

I'm a little confused about the interaction between tput and terminal sizes. It seems that the behavior of tput depends on the shell under which it is invoked, or perhaps the shell is responsible for changing terminal settings, or.... something. To reduce the problem, consider:
dash$ exec bash
bash$ trap 'echo winched' WINCH
bash$ tput cols
176
bash$ # changing terminal size now (after hitting return)
bash$ winched
bash$ winched
tput cols
150
bash$ exec dash
dash$ trap 'echo winched' WINCH
dash$ tput cols
150
dash$ # changing terminal size now (after hitting return)
dash$ tput cols
winched
150
Here, in bash, things behave (almost) as expected (I say almost, because I'm not quite sure why the WINCH handler executes twice), and the output of tput changes to match the new terminal size. However, when running in dash, the tput output does not change even though the terminal has changed size. Also note that the WINCH handler seems to be delayed by dash, and does not execute until after the next command is entered (but before it executes). What is supposed to happen here? Does tput in any way care about what the shell is doing? Is the WINCH at all relevant? I suppose the question is:
How does tput know the size of the terminal?
Also, I didn't want to clutter up the output too much, but in each shell of the example, TERM is set and infocmp $TERM prints terminfo descriptions that seem valid. (The fact that it gives any output, I think, indicates it is valid data!)

It's not obvious from the description:
-Ttype
indicates the type of terminal. Normally this option is unnecessary, because the default is taken from the environment variable TERM. If -T is specified, then the shell variables LINES
and COLUMNS will also be ignored.
but current tput calls use_env and use_tioctl for the -T option:
20171007
+ modify "-T" option of clear and tput to call use_tioctl() to obtain
the operating system's notion of the screensize if possible.
The tput manual page has a section Terminal Size, which goes into more detail.
This example (using ncurses 6.1) works as expected:
#!/bin/bash
trap "resize; tput cols; tput -T$TERM cols" WINCH
while true
do
sleep 1
done
With ncurses 6.0, you would see that difference. With other implementations, ymmv.
Regarding bash, that was discussed a while back: tput cols doesn't work properly in a script (but that q/a doesn't have any relevance to the -T option).

Related

after running a .sh file go back to the prompt i was before

example.sh:
x=0
while true
do
x=$(expr $x + 1)
clear #to print no. # same location
printf "\n\n $x"|figlet -f block
sleep 1;
done
Like, htop/cmatrix/vim/nano/bashtop,etc...
After running it i have to get back to the last prompt,
not like, cat/find/,etc...
closest solution had come up with is to, run script inside a tmux session
what i mant was, i dont want to lose my command outputs i ran before,
like nano/vim/cmatrix it clears the screen then run it, then when we exit out of it like, ^c/q , we are back where we left the prompt, with the history[last ran commands and outputs]
is there a command which does this?
┌──(kali㉿kali)-[~]
└─$ vi
┌──(kali㉿kali)-[~]
└─$ nano
┌──(kali㉿kali)-[~]
└─$ cat copy
file contents
┌──(kali㉿kali)-[~]
└─$
Here, i opened nano, i opened vim, but u cant see my inside vim or nano , but thats not the case of cat, it just print it on the same session , with vim/nano/htop terminal is clean, thats not the case in sed/cat/ps
I wanted to create a script like that,[which will not effect the terminal session(like which run in another dimention)],
I tried reading the [bashtop][1] source code, which also have same behavior, but i couldnt find the code/command which does it
vim and less and many other tools access the terminal's alternate screen and then restore the original screen when they are done. You can use tput to access the alternate screen from your shell script:
#!/bin/sh
tput smcup # begin using the alternate screen
# ...
tput rmcup # stop using alternate screen (restore terminal to original state)
Note that you don't want to remain in the alternate screen when the script ends, so you may prefer to do:
#!/bin/sh
trap 'tput rmcup' 0
tput smcup
In bashtop, they had used tput on previous updates, then they changed it to,
#!/bin/sh
echo -en '\033[?1049h' #* Switch to alternate screen
# codes to run inside
echo -en '\033[?1049l' #* Switch to normal screen

Escape newline character in heredoc on solaris

I am using bash and this works on Linux:
read -r -d '' VAR<<-EOF
Hello\nWorld
EOF
echo $VAR > trail
i.e the contents of the file on Linux is
Hello\nWorld
When i run on Solaris
trial file has
Hello
World
The newline(\n) is being replaced with a newline. How can i avoid it?
Is it a problem with heredoc or the echo command?
[UPDATE]
Based on the explanation provided here:
echo -E $VAR > trail
worked fine on Solaris.
The problem is with echo. Behavior is defined in POSIX, where interpretting \n is part of XSI but not basic POSIX itself.
You can avoid this on all platforms using printf (which is good practice anyways):
printf "%s\n" "$VAR"
This is not a problem for bash by the way. If you had used #!/usr/bin/env bash as the shebang (and also not run the script with sh script), behavior would have been consistent.
If you use #!/bin/sh, you'll get whichever shell the system uses as a default, with varying behaviors like this.
To complement #that other guy's helpful answer:
Even when it is bash executing your script, there are several ways in which the observed behavior - echo by default interpreting escape sequences such as \n - can come about:
shopt -s xpg_echo could be in effect, which makes the echo builtin interpret \ escape sequences by default.
enable -n echo could be in effect, which disables the echo builtin and runs the external executable by default - and that executable's behavior is platform-dependent.
These options are normally NOT inherited when you run a script, but there are still ways in which they could take effect:
If your interactive initialization files (e.g., ~/.bashrc) contain commands such as the above and you source (.) your script from an interactive shell.
When not sourcing your script: If your environment contains a BASH_ENV variable that points to a script, that script is sourced before your script runs; thus, if that script contains commands such as the above, they will affect your script.

VIM Unix commands printed in color

I'm using MacVim and I would like to have ! commands printed in color. For example:
In bash, the following echo statement prints Hello World in green (as expected):
$ echo -e "\033[32m Hello World"
Hello World
However, in VIM the output is not color, and the escape codes are printed:
:!echo -e "\033[32m Hello World"
[32m Hello World
How can one have VIM (and MacVim build 57 in particular) print the output of ! commands and honour ANSI color escapes.
You can't. But you can suspend the editor and drop to a shell relatively quickly;
Or you can use Ansi Filter to remove the escape sequences so you will at least not see a mess.
this one:
:!echo $(tput setaf 1)Hello world$(tput sgr0)
will print Hello world in color.
Don't use escape sequences, but named tput entries. (all times, not only in this example). read:
man teminfo; man infocmp; man tput - for more information.
based on comments I found this question very interesting.
Still searching for the better solution, but for now find this one - http://code.google.com/p/conque/ .
Allow run colored commands inside MacVim's buffer.
Don't know if this would help, but running my RSpec tests inside vim gives me colored output using the --color option. I use the following command to run the current spec file inline:
:map ,t :w\|:!rspec --color %<cr>
If you run macvim in console mode (vim, not mvim) all :! commands are redirected to the shell and executed there. They take the whole window instead of 1/3 of it, and they use whatever theme your console happens to have.
But you get ansicolors.
Your question (and its pop up done by #avocade) addressed the issue I have with some printing in my aurum plugin thus I’ve wrote (started to write, but the most significant piece of functionality is already here) the ansi_esc_echo plugin. To use it in your one you must install it, install frawor and do
execute frawor#Setup('0.0', {'autoload/ansi_esc_echo': '0.0'})
call s:_r.ansi_esc.echo("\e[33mabc")
. Currently it deals only (speaking exclusively about special characters or sequences) with carriage return, backspace (untested), tab, newline, and CSI colors.

How can I tell whether I'm in a screen?

When using screen in linux, how can I tell if I'm in a screen or not?
I could do exit and I'll exit a screen if I was in one, but if I wasn't, then I'll end up closing my terminal.
When doing screen -r, I could see if I have other screens attached, but how do I know if my current terminal is one of those attached screens?
Check $STY. If it's null, you're on a "real" terminal. If it contains anything, it's the name of the screen you're in.
If you are not in screen:
eric#dev ~ $ echo $STY
eric#dev ~ $
If you are in screen:
eric#dev ~ $ echo $STY
2026.pts-0.ip-10-0-1-71
Another way I've done it is to echo $TERM.
$ echo $TERM
screen
Since I end up doing this a lot, I added an alias into my .bashrc file:
alias trm='echo $TERM'
This way, whether in screen or not, if I just execute 'trm' it will show me whether I'm in SCREEN or elsewhere (usually XTERM).
Alternative approach to check if you are in screen.
type:
Ctrl-a ?
If you see the screen help you are in screen.
Otherwise you'll get a question mark '?' on the prompt.
Since all of the other methods here rely on environment variables (which can simply be overridden) or the command character for screen (which can also be overridden), the most foolproof way to check would be to list all the ancestors of the current process.
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | grep screen | wc -l
If it prints 1, then the current process you're running has an ancestor with the word 'screen' in the executable's name, otherwise there wasn't.
A more facile visible inspection might be obtained from:
pstree --show-parents -p $$ | head -n 1 | sed 's/\(.*\)+.*/\1/' | less
My solution to the problem is a lot simpler: just hitting TAB makes the full terminal blink (a quick video inversion) if you are inside GNU Screen.
Tested working on most Linux (Ubuntu, Kali, Debian, RaspBerry... etc) and FreeBSD, GUI and any terminal, local or remote, including CtrlAltFn ones.
As an exception for this method, please, note this (rather complex, but possible) case scenario:
1.- SSH into computer A (lets assume Linux).
2.- Enter a new screen -S AScr from remote terminal on computer A.
3.- SSH from GNU Screen AScr terminal into Computer B.
4.- Enter a new screen -S BScr from remote terminal on computer B.
You are inside a Screen on cases 2 and 4, and outside a Screen on cases 1 and 3, but the terminal will blink on cases 2, 3 and 4.
While ssh'd into a remote (older) system I noticed that $TERM indicated I was using 'screen-256color', however there was no termcap/terminfo entry for that, so I was forced to resort to the following in .bashrc to prevent the terminal from producing occasional garbage:
case $TERM in
(screen-256color) export TERM='screen'
esac
to get it to use the plain entry instead.
TL;DR, $TERM will usually indicate if you are in a screen session when ssh'd remotely. You can use case $TERM in (screen*) echo "you are in a screen session"; esac if you just want a visual clue and don't need to do something specific
Add one or more of the followings into your .bashrc
alias mysession='echo ${STY}'
alias myterm='echo ${TERM}'
alias isscreen='if test -n "$STY"; then echo " screen session: ${STY}"; else echo " NOT a screen session"; fi'
Then you can know if you are inside a screen by typing simple commands.
The problem with most of the above answers is that we might be in a subshell of an attached screen session. Or we might be opening a shell to a remote host from within a screen session. In the former case, we can walk the process tree parentage and match for the screen program name. In the latter case, most of the time, we can check the TERM variable for something like screen*.
My answer os similar to /u/Parthian-Shot but not so dependent on the pstree utility; the options he use are not available to me. On the other hand, my implementation is still Linux-dependent: for non-Linux systems, one must tweak the ps command; for systems with older shells that don't support arrays, you'll have yet more work-arounds. But anyway:
ps_walk_parents() {
local tmp
local ppid=$PPID
while [[ $ppid != 1 ]]; do
tmp=($( ps -o ppid,comm -p $ppid ))
ppid=${tmp[0]} # grab parent pid
echo ${tmp[1]} # output corresponding command name
done
}
if [[ "$TERM" =~ screen* ]] || ps_walk_parents |grep -qxi screen ; then
# we are in a screen terminal
fi
We could optimize our function a bit to stop searching if/when a process parent matches the target command name ("screen"), but in general, the function will only hit 2 to 3 iterations. Presumably you want to put this code in some startup initialization such as .bashrc or .profile or something, so again, not worth optimizing.
screen -ls can tell you.
Outside screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Detached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.
Inside a screen:
$ screen -ls
There are screens on:
16954.pts-1.auds916 (Attached)
242.pts-8.auds916 (Detached)
2 Sockets in /tmp/screens/S-glennj.

How do I launch an editor from a shell script?

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.

Resources