Clear terminal screen with a two line prompt and keep both lines visible - bash

I have a two line prompt like below. Is there a command like clear that will clear the screen but keep both lines of the prompt visible?
~/current/directory git-branch*
$ echo 'hello...

short: no, there's no such command.
long: you could write a script. Here's a brief introduction to the topic.
The clear program clears the whole screen. Your shell will draw a new prompt (at the top of the newly cleared screen). But suppose that you wanted to clear parts of the screen before your command completes, and returns to the shell.
Most terminals that you would use support the ANSI escape sequence which clears from the current cursor location to the end of the screen, which is the terminfo capability ed:
clr_eos ed cd clear to end of
screen (P*)
shown by infocmp as ed=\E[J.
You can use it in a script, e.g., using tput:
tput ed
This is one of the areas where "ansi.sys" differs from the ANSI standard (actually ECMA-48, see 8.3.29 ERASE IN PAGE). ansi.sys clears the entire screen when it receives
printf '\033]J'
Some people hard-code this into scripts, and assume that "ansi.sys" matches the standard. See for example How do I get color with VT100? in the ncurses FAQ.
Noting a comment about how to test this: likely there is nothing on your screen below the prompt. So typing tput ed may appear to do nothing. As noted above, it clears below the cursor. If you want to clear above the (2-line) prompt, that's a little more complicated:
save the cursor position
move the cursor up two lines
clear before the cursor
restore the cursor position.
If your prompt happens to be on the first line of the screen, this could be detected using the cursor position report. But that's more complicated to do than the question as phrased would anticipate. Assume that there's space above:
tput sc
tput cuu 2
tput cub 999
printf '\033[1J'
tput rc
A regular printf rather than tput is used here, because there's no predefined terminfo (or termcap) capability defined for that type of erase.
If you wanted to handle the case where the prompt starts in the top line of the terminal, you'd have to find the current line number and decide whether to do the clearing above (or not).
Further reading:
Re: cursor position in a variable

Related

How do programs like man, screen, and vim create temporary overlays?

Several *NIX commands, such as screen, man, vim and others, create a temporary canvas/screen/overlay in a shell environment. When such programs execute, they cover or hide whatever content was displayed in the terminal before — almost like a "full screen" mode, within the terminal window. When they terminate, however, they reveal or restore whatever had been on the terminal before.
In the example below, I create some filler text on the screen, then invoke man bash. The man page opens up and covers all other characters on the terminal display. When I close the man page, the characters that had been covered up are again shown.
Before
While an example full-screen program is running
After
I would expect that programs writing to stdout/stderr could accomplish the first step (replacing the content of the terminal with program-specific content), but then it would produce a ton of text that I could scroll through, and therefore couldn't do the second step: restoring the contents of the terminal. That means that somehow either the program memorizes the previous contents of the screen and re-outputs them (I doubt it?), or it creates some sort of sub-window within a terminal and something else keeps track of the previous contents of the terminal.
My Question
How can I accomplish that behavior in my own program and/or script?
Perhaps I should use curses/ncurses, tput, termcap/terminfo, or ANSI escape sequences?
Update:
This revised question is essentially the same as https://unix.stackexchange.com/questions/27941/show-output-on-another-screen-and-return-to-normal-when-done. (I hadn't found it when I had written this question despite lots of searching.) The difference is that my question is more general (any language) whereas that question is specific to Bash. The answers to both questions are essentially the same. If it's too similar to a question on another site, feel free to close it here for that reason.
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.

how to get current terminal color pair in bash

I would like to query and store the current terminal color pair in BASH e.g.:
#!/bin/bash
#some ANSI colour escape sequences
red="\033[0;31m"
grn="\033[0;32m"
blu="\033[0;34m"
def="\033[0;00m" # default
echo -e "Change to ${red} red to ${def} default to ${blu} blue."
# now store the current color (which happens to be blue) e.g.:
cur=????
echo -e "Change to ${grn} green and back to what I had before ${cur}"
echo -e "This would be in blue if variable cur contained e.g.: 0;34m."
echo -e "Back to default${def}"
exit 0
The answer that eludes me is how to capture the current color
cur=????
The question was about the current color, not the cursor position.
Both are "nonstandard" (though the latter, cursor position report is implemented by anything which has a valid claim to "VT100 emulator").
However, xterm implements a set of escape sequences referred to as dynamic colors, which predate the ANSI color functionality. Those set the working colors including text foreground and background. I modified this in 2002 to allow an application to send the sequence with a "?" rather than a color to tell xterm to return the color value, e.g.,
OSC 1 1 ? ST
using the notation given in XTerm Control Sequences
You can't; there is no standard control sequence to report the current cursor attributes.
What does exist, however, is a sequence to save and restore the current cursor position and attributes:
\e7 (DECSC) will save the cursor position and attributes.
\e8 (DECRC) will restore the saved cursor position and attributes.
There is no standard way to restore only the cursor attributes; however, as rici mentioned, you can get a report of the current position using \e[6n (DSR), then use the response to manually "un-restore" the cursor position after restoring its position and attributes.
Again, though, it's probably easier (and better) to just keep track of the colors in your application, rather than making the terminal responsible for that.
It's important to understand that the terminal state has nothing to do with bash. Bash doesn't care. It simply reads from stdin and writes to stdout and stderr. (See Note 1)
All terminal effects are implemented by the terminal emulator you happen to be using, of which there are many. In a graphical environment, you might be using, for example, xterm or konsole. You'll need to search the documentation for those emulators for specific terminal control codes which they interpret.
As far as I know, there is no standard code to get a report of the current terminal state, other than the cursor position (ESC[6n).
So your best bet is to remember the changes you made when you make them.
You can find a list of the standard codes implemented by the Linux console using man console_codes (although few people use the Linux console these days); most of those are also interpreted by xterm and other graphical consoles. There's an list of xterm sequences in Thomas Dickey's xterm site; it's a more or less de facto standard for terminal emulators but, as I said, you'll need to search in each emulator's documentation for idiosyncratic control sequences.
Notes
In interactive mode, bash uses a library called readline to help it handle some terminal effects. In particular, readline tries to maintain the current console cursor position, although it is easy to fool it. In PS1 you need to surround console control sequences with \[ and \] precisely because readline does not know that they are control sequences.
What I understood, is that u are asking to to get the default profile color of the user, of which u have change color of!
Eg: User is using 'Bright Green font color on Black background', you change it to 'Red font color on White background'. Now how to get/know the default colors and set them back to it!
You can use the sequence \033[0m in bash [also for command prompt (batch scripting) / powershell (ps scripting)]

Is it possible to replicate the effect of vim's `zz` in bash?

In Vim, executing zz in normal mode will take the line the cursor is currently on, and move that line, together with the cursor, to the vertical center of the current window.
Is there a way to replicate this behavior in bash, to move the current command prompt to the vertical center of the screen, and scroll the command buffer along with it?
I am posting on StackOverflow instead of Unix/Linux because I am open to solutions that require writing custom code if bash does not natively support this.
Vim controls the entire area of the screen. Bash is only responsible for the input line. It has no idea about the contents of the rest of the screen, which is/was under control of other programs, and cannot reposition it.
Note that the contents of the screen nornally cannot be read by a program running on it. The only way to know what's on the screen is to start from a clean state and account for every single character and terminal command printed. Vim does just that; Bash does not and can not.
n.m. has already explained that bash itself cannot do it. However, you still might be able to send commands directly to the underlying terminal to achieve an effect similar to what you want. For example, assuming that your bash input line is somewhere below the middle of the screen, the following will scroll down by sending a couple of empty lines and then putting you into the middle of the screen:
declare -i L; declare -i M; L=`tput lines`/2; M=$L-1; for (( c=1; c<=$L; c++ )); do echo; done; tput cup $M
Note that this doesn't work when your somewhere in the upper half of the screen (it will put you into the middle of the screen, but will not scroll back).
For more info see man tput and man terminfo.

Unable to turn off automatic margins by termcap in Mac

I need to turn automatic margins off according the following statement from Screen's manual in my Mac
If your terminal is a "true"
auto-margin terminal (it doesn't allow
the last position on the screen
to be updated without scrolling the screen) consider using a version
of your terminal's termcap that
has automatic margins turned off.
How can you turn automatic margins off by your terminal's termcap?
Most terminal emulators, including the mac default terminal, are not "true auto-margin terminals" in the sense being discussed here - they emulate a vt100-series terminal, which had "smart" wraparound. You can check by running cat and typing to the end of the last line - after you type the last character, the cursor remains at the end of the line (highlighting the character you just typed) until you type another character.
The only consequence of a 'true auto-margin terminal' is that a character cannot be displayed in the lower right hand corner (though some programs are able to work around that by shifting a character into place with ich/ich1)
According to XTerm Control Sequences, this sequence should do what was asked:
CSI ? 7 l
That is,
printf '\033[?7l'
The 7 is documented as
Ps = 7 -> Wraparound Mode (DECAWM).
and the final character l (lowercase L) denotes this as a reset rather than a set control.
For whatever reason, the terminfo name for this is more obscure: "automatic margins". These terminfo capabilities deal with the feature (see terminfo(5)):
auto_right_margin am am terminal has auto‐
matic margins
enter_am_mode smam SA turn on automatic
margins
exit_am_mode rmam RA turn off automatic
margins
Interestingly, the vt100-nam terminal description in ncurses (which apparently no one uses) initializes the terminal to use automargins margins using this string:
rs2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h,
(the \E[?7h sets it), and asserts that the terminal does not use automatic margins by cancelling am. It also has the terminfo capabilities rmam and smam. So you could do this to prove that it works:
tput rmam
stty columns 999
ps -efwwwwwl
and (for the ordinary user) see the ps listing nicely truncated against the right margin of the terminal window.
The other variants vt220-nam and vt320-nam appear correct...
By the way, for Mac, you would use the terminfo names such as rmcup rather than the termcap RA, because OSX uses ncurses' tput (terminfo) rather than the BSD variant.
Further reading:
tput, reset - initialize a terminal or query terminfo
database
history section for tput
history section for tset
Occasionally someone asks about suppressing automargins because they suppose that terminals can pan/scroll left/right to show the information which was not wrapped to a new line. Terminals which do this are rare, and OSX Terminal is not one of those. It behaves like a subset of xterm, which itself emulates the series of DEC terminals vt52/vt100/vt220/etc. In this question, OP is concerned/confused about this paragraph from the screen manual:
If your terminal is a "true" auto-margin terminal (it doesn't allow the
last position on the screen to be updated without scrolling the screen)
consider using a version of your terminal's termcap that has automatic
margins turned off. This will ensure an accurate and optimal update of
the screen in all circumstances. Most terminals nowadays have "magic"
margins (automatic margins plus usable last column). This is the VT100
style type and perfectly suited for screen. If all you've got is a
"true" auto-margin terminal screen will be content to use it, but
updating a character put into the last position on the screen may not
be possible until the screen scrolls or the character is moved into a
safe position in some other way. This delay can be shortened by using a
terminal with insert-character capability.
That last position on the screen refers to the lower-right corner of the terminal. In the normal case, if your cursor is on the lower-right corner and you print a character, you would expect the display to scroll up by one line and show the character on the next line. Also (because terminals can be implemented in different ways), some could scroll up when you print a character in the last position. The VT100 does not do this. Not only does it not scroll up in that case, but it ignores non-printing characters while on the margin (see xterm FAQ That description of wrapping is odd, say more?). There is a terminfo flag xenl which is set to show when the terminal does this special behavior. About a third of the terminal descriptions in the terminal database have this flag. While most of those are for terminals which you likely will never encounter, keep in mind that the advice in the manual page was written back in an era when those other terminals were as likely to be found as a VT100-lookalike. The early change-history for screen is poor, but the text was in screen's second posting to Usenet in 1992. The initial posting in 1987 said something similar:
Screen
never writes in the last position of the screen, unless the boolean
capability LP is found in the termcap entry of the terminal.
Usually,
screen
cannot predict whether or not a particular terminal scrolls when
a character is written in the last column of the last line;
LP indicates that it is safe to write in this position.
Note that the LP capability is independent of am (automatic
margins); for certain terminals, such as the VT100, it is reasonable
to set am as well as LP in the corresponding termcap entry
(the VT100 does not move the cursor when a character is written in
the last column of each line).
The later wording reflects the fact that the terminfo system was prevalent, and the name LP was not termcap name chosen for corresponding with xenl (it is xn).
The point of all of this is that screen attempts to convert between programs writing to different terminal types and make them all appear like one type of terminal — which means that it tries to put text on the terminal's display in all of the locations. The lower-right corner is a problem because some terminals would scroll up, spoiling the attempt to write there. As a workaround, some terminals provided an alternative:
using a different mode (insert),
put the cursor on the next to last position of the display,
write characters to fill in, pushing a character into the last position, and
turn insert-mode off once it is done (otherwise a nuisance).
About two thirds of the descriptions in the terminal database have the capability to do this insert-mode (smir). That still was not perfect, but it certainly was worth mentioning in 1992. About a quarter implement a similar similar feature ich1. Some implement both (and vi could get confused by those, by trying to do both methods).
VT100-lookalikes provide a third way to write that last position; screen checks for and uses whatever is there.
If I understand you correctly you're looking to set the autowrap feature to NO using terminfo database. If so I believe you can use the -nam flag to turn it off - something like vt100-nam should do it. You can also check by looking at the man pages for terminfo.
If this solves your question, mark this up. (^_^) If not... well comment back and I'll check again for you. Cheers!
Update: There's also a shortcut that may apply to you to toggle the wrap off and on. Check out the shortcut sheet here. And additional information for Screen can be found here (search for wrap). You can also check here on how to use setterm (section 17.14 Changing the Terminal Settings). Also check here for examples of changing settings.
Good luck again. (^_^)

Fastest way(s) to move the cursor on a terminal command line?

What is the best way to move around on a given very long command line in the terminal?
Say I used the arrow key or Ctrl-R to get this long command line:
./cmd --option1 --option2 --option3 --option4 --option5 --option6 --option7 --option8 --option9 --option10 --option11 --option12 --option13 --option14 --option15 --option16 --option17 --option18 --option19 --option20 --option21 --option22 --option23 --option24 --option25 --option26 --option27 --option28 --option29 --option30 --option31 --option32 --option33 --option34 --option35 --option36 --option37 --option38 --option39 --option40 --option41 --option42 --option43 --option44 --option45 --option46 --option47 --option48 --option49 --option50
Now I need to move (starting from the beginning or the end of the line) the cursor to --option25 to modify something there.
What is the fastest way to get there? What I usually do is Ctrl-A to get to the beginning and then repeatedly Alt-F to move forward, word by word (or Ctrl-E to go the end and Alt-B to then go backward). But on a long line that takes too much time. There must be a way to search and jump directly to the part I need to modify, e.g. option25?
To be clear, you don't want a "fast way to move the cursor on a terminal command line".
What you actually want is a fast way to navigate over command line in you shell program.
Bash is very common shell, for example.
It uses Readline library to implement command line input. And so to say, it is very convenient to know Readline bindings since it is used not only in bash. For example, gdb also uses Readline to process input.
In Readline documentation you can find all navigation related bindings (and more):
http://www.gnu.org/software/bash/manual/bash.html#Readline-Interaction
Short copy-paste if the link above goes down:
Bare Essentials
Ctrl-b Move back one character.
Ctrl-f Move forward one character.
[DEL] or [Backspace] Delete the character to the left of the cursor.
Ctrl-d Delete the character underneath the cursor.
Ctrl-_ or C-x C-u Undo the last editing command. You can undo all the way back to an empty line.
Movement
Ctrl-a Move to the start of the line.
Ctrl-e Move to the end of the line.
Meta-f Move forward a word, where a word is composed of letters and digits.
Meta-b Move backward a word.
Ctrl-l Clear the screen, reprinting the current line at the top.
Kill and yank
Ctrl-k Kill the text from the current cursor position to the end of the line.
M-d Kill from the cursor to the end of the current word, or, if between words, to the end of the next word. Word boundaries are the same as those used by M-f.
M-[DEL] Kill from the cursor the start of the current word, or, if between words, to the start of the previous word. Word boundaries are the same as those used by M-b.
Ctrl-w Kill from the cursor to the previous whitespace. This is different than M- because the word boundaries differ.
Ctrl-y Yank the most recently killed text back into the buffer at the cursor.
M-y Rotate the kill-ring, and yank the new top. You can only do this if the prior command is C-y or M-y.
M is Meta key.
For Max OS X Terminal you can enable "Use option as meta key" in Settings/Keyboard for that.
For Linux its more complicated.
Update
Also note, that Readline can operate in two modes:
emacs mode (which is the default)
vi mode
To switch Bash to use vi mode:
$ set -o vi
Personaly I prefer vi mode since I use vim for text editing.
Bonus
In macOS Terminal app (and in iTerm too) you can Option-Click to move the cursor (cursor will move to clicked position). This even works inside vim.
Since this hasn't been closed yet, here are a few more options.
Use Ctrl+x followed by Ctrl+e to open the current line in the editor specified by $FCEDIT or $EDITOR or emacs (tried in that order).
If you ran the command earlier, hit Ctrl+r for a reverse history search and type option25 (in this case). The line will be displayed. Hit Tab to start editing at this point.
Use history expansion with the s/// modifier. E.g. !-2:s/--option25/--newoption/ would rerun the second-to-last command, but replace option25. To modify the last ./cmd command, use the !string syntax: !./cmd:s/--option25/--newoption/
Any delimiter may be used in place of / in the substitution.
If editing the previous line, you can use quick substitution: ^--option25^--newoption
Character search. This was mentioned by Pax, and can be done in regular emacs-mode with Ctrl+] for forward search, and Ctrl+Alt+] for backward search.
I recommend the second option. Ctrl+r is really handy and fast, no mucking about with editors, and you see the results before the command is run (unlike the history expansions).
Hold down the Option key and click where you'd like the cursor to move, and Terminal rushes the cursor that precise spot.
I tend to prefer vi editing mode (since those keystrokes are embedded into my spinal cord now (the brain's not used at all), along with the CTRL-K, CTRL-X from WordStar 3.3 :-). You can use the command line set -o vi to activate it (and set -o emacs to revert).
In Vi, it would be (ESC-K to get the line up first of course) "f5;;B" (without the double quotes).
Of course, you have to understand what's on the line to get away with this. Basically, it's
f5 to find the first occurrence of "5" (in --option5).
; to find the next one (in --option15).
; to find the next one (in --option25).
B to back up to the start of the word.
Let's see if the emacs aficionados can come up with a better solution, less than 5 keystrokes (although I don't want to start a religious war).
Have you thought about whether you'd maybe like to put this horrendously long command into a script? :-)
Actually, I can go one better than that: "3f5B" to find the third occurrence of "5" then back up to the start of the word.
Use Meta-b / Meta-f to move backward/forward by a word respectively.
In OSX, Meta translates as ESC, which sucks.
But alternatively, you can open terminal preferences -> settings -> profile -> keyboard and check "use option as meta key"
After running the command once, run fc
It will launch $EDITOR with the previous command, then you can use your regular editor to modify the command. When you save and exit, the file will be executed.
..but, as Pax said - the command line isn't particularly good for editing absurdly long lines - why not make the command into a script?
If you want to move forward a certain number of words, hit M-<n> (M- is for Meta and its usually the escape key) then hit a number. This sends a repeat argument to readline, so you can repeat whatever command you want - if you want to go forward then hit M-<n> M-f and the cursor will move forward <n> number of words.
E.g.
$|echo "two three four five six seven"
$ M-4
(arg: 4) echo "two three four five six seven"
$ M-f
$ echo "two three four| five six seven"
So for your example from the cursor at the beginning of the line you would hit, M-26 M-f and your cursor would be at --option25| -or- from the end of the line M-26 M-b would put your cursor at --|option25
Incremental history searching
in terminal enter:
gedit ~/.inputrc
then copy paste and save
"\e[A": history-search-backward
"\e[B": history-search-forward
"\e[C": forward-char
"\e[D": backward-char
all you need to do to find a previous command is to enter say the first 2 or 3 letters and upward arrow will take you there quickly say i want:
for f in *.mid ; do timidity "$f"; done
all i need to do is enter
fo
and hit upward arrow command will soon appear
It might not be the fastest, but this need to be here, some reading about ANSI cursor movements
ANSI escape sequences allow you to move the cursor around the screen at will. This is more useful for full screen user interfaces generated by shell scripts, but can also be used in prompts. The movement escape sequences are as follows:
- Position the Cursor:
\033[<L>;<C>H
Or
\033[<L>;<C>f
puts the cursor at line L and column C.
- Move the cursor up N lines:
\033[<N>A
- Move the cursor down N lines:
\033[<N>B
- Move the cursor forward N columns:
\033[<N>C
- Move the cursor backward N columns:
\033[<N>D
- Clear the screen, move to (0,0):
\033[2J or \033c
- Erase to end of line:
\033[K
- Save cursor position:
\033[s
- Restore cursor position:
\033[u
(...)
Try putting in the following line of code at the prompt (it's a little clearer what it does if the prompt is several lines down the terminal when you put this in): echo -en "\033[7A\033[1;35m BASH \033[7B\033[6D" This should move the cursor seven lines up screen, print the word " BASH ", and then return to where it started to produce a normal prompt.
Examples:
Move the cursor back 7 lines:
echo -e "\033[7A"
Move the cursor to line 10, column 5:
echo -e "\033[10;5H"
Quickly echo colors codes, to colorize a program:
echo -e "\033[35;42m" ; ifconfig
using option key and using a click the place you want to place the cursor with mouse or touchpad is you are using Mac build-in terminal.
One option is to use M-x shell in emacs. That provides all editing facilities and keystrokes that emacs has, so C-s can be used to search the text option25, for example.
(But I'd still prefer to be in the real terminal shell instead if someone can point me to good search and edit facilities.)
Use the mouse
Sometimes, the easiest way to edit a commandline is using a mouse. Some previous answers give a command to open your current line in your $EDITOR. For me (zhs with grml config) that combination is Alt+e. If you enable mouse in your editor, you can make use of it.
To enable mouse in Vim, add this to your ~/.vimrc
set mouse=a
set ttymouse=xterm2
If you then want to do a text selection in terminal (instead of passing the mouseclick to vim), hold Shift when you click; this is terminal specific, of course.
Sysadmins should not be afraid of the mouse.
In Cygwin, you can activate such feature by right-clicking the window. In the pop-up window, select Options... -> Mouse -> activate Clicks place command line cursor -> Apply.
From now on, simply clicking the left mouse button at some position within the command line will place the cursor there.
first:
export EDITOR='nano -m'
then:
CTRL+X CTRL+E in sequence.
You current line will open in nano editor with mouse enable. You can click in any part of text and edit
then CTRL+X to exit and y to confirm saving.
I made a script to make the command line cursor move on mouse click :
Enable xterm mouse tracking reporting
Set readline bindings to consume the escape sequence generated by clicks
It can be found on github
More info on another post
Will work if echo -e "\e[?1000;1006;1015h" # Enable tracking print escape sequences on terminal when clicking with mouse

Resources