Using the alternate screen in a bash script
You can switch to the alternate screen using this command:
$ tput smcup
And back with:
$ tput rmcup
These commands just output the appropriate escape sequences for your terminal. If it is an XTERM they will be equivalent to the (more known but less elegant or portable):
$ echo -e "\e[?1049h"
And:
$ echo -e "\e[?1049l"
For more terminal control commands see man 5 terminfo
.
after running a .sh file go back to the prompt i was before
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
Populating a variable from a script that needs to write to the terminal
Don't rule out result=$(inner.sh)
just yet. If you want to display interactive prompts or dialogs in the script, do those on stderr, and have it write only the answer to stdout. Then you can have your cake and eat it too: interactive prompts and the result saved to a variable.
For example, dialog
does exactly this if you use --output-fd 1
to tell it to write its answer to stdout. It uses curses to draw a dialog to the alternate screen but does it all on stderr.
$ value=$(dialog --keep-tite --output-fd 1 --inputbox title 10 40)
<dialog box shown>
<type "hello">
hello
(via Ask Ubuntu: How to get dialog box input directed to a variable?)
The script you posted can be made to do the same thing. It currently writes to stdout. Put exec 3>&1 1>&2
at the top so it'll write to stderr instead, and change the final echo ${options[$selected]}
to echo ${options[$selected]} >&3
to write the answer to stdout. That'd get rid of the need for the caller to juggle file descriptors.
That said, prompts are not very UNIX-y. Consider eschewing interactivity entirely in favor of command-line arguments, configuration files, or environment variables. These options are better for power users who know how to use your script and want to automate it themselves.
My main purpose here is to commit a
latest-stable-config
from a selection of my last backups, which in my opinion needs the human judgement of when to consider a backup as appropriately stable.
The way I'd personally handle it is by writing a script with a couple of modes. Let's call it backups
. backups --list
would display a list of backups. You pick one and then call backups --commit <id>
which would commit the named config. backups
with no arguments would display usage for the unfamiliar user.
$ backups
Usage: backups --list
or: backups --commit <id>
Manages a selection of backups. Use --list to list available backups
and --commit to commit the latest stable config.
$ backups --list
4ac6 10 minutes ago
18f2 1 day ago
3019 7 days ago
$ backups --commit 4ac6
screen: how to turn on alternate screen?
UPDATE : I had forgotten about a feature of screen
that disables alternate screen support by default.
Add altscreen on
to your $HOME/.screenrc
to enable it. This is probably all you have to do; all the messing about with $TERM
, $TERMCAP
, and $TERMINFO
is probably unnecessary. I'll leave the rest of this answer here anyway.
I've had this in my own .screenrc
so long it slipped my mind.
To enable this feature for the current session, type your screen
escape character (Cntrl-A by default) followed by :altscreen on
Enter.
Without this, screen
won't respond to the escape sequences, even if they're defined in terminfo or termcap.
vim
(and less
, and most other curses-based full-screen programs) use the smcup
and rmcup
strings defined by the terminfo entry for your terminal. (These are referred to as ti
and te
, respectively, in the older termcap system). smcup
switches to the alternate screen, and rmcup
switches back to the primary screen.
If your terminfo entry doesn't have these strings, programs won't be able to do that.
The screen command, by default, sets your $TERM
to "screen"
. Apparently the "screen" terminfo entry doesn't have smcup
and rmcup
.
If you feel like hacking terminfo entries, you can modify your existing information for "screen" to add smcup
and rmcup
. You'll need the infocmp
command to convert your terminfo to a text, and tic
to convert it back to the binary form used by terminfo.
A simpler solution is to set your $TERM
environment variable to whatever it was before you invoked the screen
command. Almost all terminal emulators these days are based on the old DEC VT100, so they should be sufficiently compatible.
On my system, for example, when I login I have TERM=xterm
; it's likely something else on MacOS. Within a screen
session, by default, I'd have:
$ echo $TERM
screen
I could change it to xterm
like this:
$ export TERM=xterm
(Again, replace "xterm" by whatever $TERM
is on your system.)
You can also add
term xterm
to your $HOME/.screenrc
. In fact screen
has a number of options for tweaking your termcap/terminfo settings; man screen
and search for "terminfo" for the gory details.
How to setup screen using a bash script
Try the following, it will open a new screen session with a bash which will change the directory and open a new bash with this directory as current:
screen -S work bash -c 'cd myDir && exec bash'
Adding -d -m
to run it in detached mode. And after reattaching you will be in myDir
:
screen -S work -d -m bash -c 'cd myDir && exec bash'
Better solution
The following code will create a detached screen with 3 screens each running myCommand1/2/3
in directory myDir1/2/3
.
cd myDir1
screen -S work -d -m
screen -S work -X exec myCommand1
screen -S work -X chdir myDir2
screen -S work -X screen
screen -S work -X exec myCommand2
screen -S work -X chdir myDir3
screen -S work -X screen
screen -S work -X exec myCommand3
cd -
Note the last cd -
that will return you back to your original working directory.
Finally just use screen -r work
to attach your running screen session.
How do programs like man, screen, and vim create temporary overlays?
How do these programs accomplish that behavior?
ANSI escape sequences. Try running this script:
#/bin/bash -
tput smcup
echo 'Hello world!'
sleep 3
tput rmcup
Using infocmp
, you can see underlying sequences that create this overlaying effect, e.g:
$ infocmp -1 | grep 'rmcup\|smcup'
rmcup=\E[?1049l\E[23;0;0t,
smcup=\E[?1049h\E[22;0;0t,
is this behavior shell-dependent or system-dependent?
None, it depends on whether the terminal emulator supports save/restore operations.
Related Topics
What's the Difference Between "Statically Linked" and "Not a Dynamic Executable" from Linux Ldd
How to Add Users to Docker Container
Imagemagick Security Policy 'Pdf' Blocking Conversion
Maximum Length of Command Line Argument That Can Be Passed to Sql*Plus
How to Remove the Last Character of a File in Unix
Run a Shell Command When a File Is Added
How to Handle More Than 10 Parameters in Shell
Is Gettimeofday() Guaranteed to Be of Microsecond Resolution
How to Open a Socket and Pass It to Another Process in Linux
How to Delete an Exported Environment Variable
Recursively Counting Files in a Linux Directory
How to Find All Serial Devices (Ttys, Ttyusb, ..) on Linux Without Opening Them
How to Redirect Output of an Already Running Process
Make $Java_Home Easily Changable in Ubuntu
Pipe Only Stderr Through a Filter
How to Simulate Just One Enter in Command Line After Executing a Jar File