"CLS" Equivalent in BASH? - bash

How do you clear the entire terminal in BASH, like the command prompt's cls command?
clear doesn't work because it doesn't actually clear anything, it just scrolls down.

As far as I know, there isn't a way to do this any better than what clear does with bash.
I think it's a feature that could be built into the terminal you're using though. I know the Mac Terminal app has a 'Clear Scrollback' menu option (command + k) that does what you're asking for.

Why don't you try Ctrl+l (control, lowercase "L"). This works in most shells (err terminals)...
In OSX terminal -
Command ⌘+l (command, l) leads to removing last typed command from display.
Command ⌘+k (command, k) leads to removing/clearing all display buffer.
reset (type this in terminal) leads to reset of terminal in case display becomes garbled.
not sure of equivalent in other unix flavors.

You're probably looking for the reset command.
However, the scroll-back buffer is not a feature of bash but of the terminal program. You didn't say what terminal program you were using.

xterm will allow the escape sequence ESC [3J to clear the scroll back, so you could do:
alias cls="clear; printf '\033[3J'"

Short Answer
clear && clear
or
tput reset
Other Ways
Here are all the ways you can clear the terminal screen in Unix:
clear # only clear visible screen
clear && clear # clear buffer as well
tput clear # same as clear but by sending escape seq
reset # clear + reset internal terminal state + 1sec delay
tput reset # same as reset but without 1sec delay
stty sane # don't clear screen but reset some terminal options
echo -e "\033c" # same as tput reset but hardcoded escape seq
printf "\033c" # same as tput reset but hardcoded escape seq
setterm -reset # same as tput reset, setterm has friendlier commands
Long Answer
The clear command only clears the visible screen but not the buffer so you can do Shift+PageUp to scroll up in the terminal and still view previous outputs. If you want to get same result as cls then do clear twice like clear && clear.
Another related command is reset which (I believe) resets the internal state of the terminal program. Unfortunately, this command includes 1 second of delay to support really old terminals. So if you are not ok with that kind of delay then use tput reset which seems to do same thing as reset minus the delay.
But what does tput do? In Unix, you can send terminal all kinds of ASCII character sequences which are interpreted as commands by the terminal. This allows you to do funky things like blink or color the text or turn off echo (during password typing) or set terminal options or do clear or reset. This you can send by tput clear or tput reset. The clear and reset command are equivalent but they run from the binaries that comes with your distro and may do additional stuff. The setterm -reset is similar to tput reset. Setting terminal using setterm is usually better because unlike tput it has more readable options in general case however we here use tput because it's smaller in length :).
You might have also seen people using things like echo -e "\033c" or printf "\033c" which is equivalent to tput reset but the escape sequence is now hard coded. The tput looks up terminal properties and uses the right escape sequence.
Another related command is stty sane which actually doesn't do any screen clearing but it sets many of the terminal options to defaults so if your terminal looks garbled or if terminal stays blank when you type (for example, because you printed binary file to terminal with escape sequence to turn off echo) then this command might help. For extreme garbled terminal cases, you can use all of the available resetting techniques in the sequence. I've alias like this for such occasions:
alias cls='tput reset'
alias clshard='reset; stty sane; tput rs1; setterm -reset; tput reset'
Related
What's the equivalent of the “cls” command from Windows/DOS?
What commands can I use to reset and clear my terminal?

Use ⌘+K. It removes the entries so I can't scroll up anymore.
So ⌘+K to clear everything including scrolling.
Ctrl+L to clear terminal window but still be able to see everything when scrolling up.

In ~/.bashrc, the perfect cls is:
cls () {
printf -- '%b' '\033c'
return $?
}

The clear command works for me.
But I personally find it impractical, because, for me, it clears the scrollback permanently and irreversibly. However, often I want just to insert some "marker"/"separator" into the scrollback, in order to be able to visually distinguish the "recent scrollback" from the "too old scrollback" (but sometimes ability to see the "too old scrollback" would be still useful). So I use something like:
yes '' | head -n100
That inserts 100 empty lines into the scrollback. (Inspired by this answer. You can vary the number of lines, of course.)

Related

Is there a way to reproduce 'less' screen behavior in bash? [duplicate]

This question already has answers here:
Using the "alternate screen" in a bash script
(3 answers)
Closed 9 months ago.
I try to make a simple bash script that runs multiple tools, like dehader, cppcheck and a bunch of custom tools, and for readability, it cleans the terminal between each tool, and wait for the user to press the enter key before running the next tool.
clear
rm *.o
echo "removed object files"
rm __pycache__
echo "removed python cache files"
echo "everything cleaned, press enter to continue"
read a
clear
deheader
echo "deheader done, press enter to continue"
read a
clear
cppcheck
echo "cpp check done, press enter to exit"
read a
clear
Simple reproduction of what my script does
But I don't like this solution, because I want this script to execute in another screen (I don't know how to call it exactly), just like less does. This way, I could keep my terminal just like it was before the script call. Even if they aren't close to the less behavior, any suggestions that could help me are welcome.
I searched online what I could do to reproduce this behavior, but didn't find anything. I'm starting to doubt that's even possible.
Note: I don't want the 'scrolling' less behavior. I mean, there's no problem if I have to use it, but I don't particulary want it.
I think you want to run a new Terminal window and get back the prompt in your current Terminal window. If so, start a new Terminal that runs a command with lots of output and pipe it through less:
xterm -e "ls -lR / | less" &
The & runs the command in the background and gets you your prompt back in the current Terminal window.
Thanks to the comments, I figured it out.
From what I can understand, there are two ways to do it with the "cursor addressing mode":
By using tput smcup/rmcup
By entering/exiting the "cursor addressing mode" manually, when priting the escapes sequences related
This mode in terminal-implemented and is not supported by all terminals - and not always in the same way, for example multiple terminals don't reset the cursor position after entering this mode, so don't forget to clear your terminal - but is fortunately supported by a large majority of modern terminal emulators.
smcup/rmcup
Simply use the tput smcup command, and then, restore it using tput rmcup.
Example:
# save, clear screen
tput smcup
clear
# example "application" follows...
read -n1 -p "Press any key to continue..."
# example "application" ends here
# restore
tput rmcup
source
Escape sequence
You can enter this mode using printf \\33\[\?1047h, then leave it using printf \\33\[\?1047l.
Example:
# save, clear screen
printf \\33\[\?1047h
clear
# example "application" follows...
read -n1 -p "Press any key to continue..."
# example "application" ends here
# restore
printf \\33\[\?1047l
more informations
Try to avoid using both methods in the same code, or using one method to enter this mode and another to exit it, as it could lead to unexpected behavior.
Personnaly, I prefer the tcup method as it's more readable and supported by all Unix systems.

zsh command line editor: go back to previous lines when entering a command

Note that I'm NOT talking about previous lines in the history. I'm talking about previous lines in the current multiline command.
When I type a multiline command in zsh, for instance (_ indicates the cursor):
$ for i in {1..5}; do
for> echo i_
At this point I might change my mind and want to let i loop through {1..10} instead, so I need to go back to the previous line. However, I can't figure out how to do this, as ⌫, or ←, or C-b, or whatever I can think of all stops at the beginning of the second line. So, is it possible at all to move back? Thanks in advance.
In fact, this is not limited to zsh. For instance, I've never figured this out in bash either.
I've already spent a fair amount of time Googling without any findings, so please excuse me and blame my Google-fu if this is obvious.
For your reference, I'm using Emacs keybinding, and
$ bindkey | grep delete
"^D" delete-char-or-list
"^H" backward-delete-char
"^[[3~" delete-char
"^?" backward-delete-char
Not sure whether this will help.
Here is how you would visual mode in bash's vim mode.
Inside .bashrc put the following lines.
set -o vi
# I do not remember which one of these is used by `v`, so I set both
export VISUAL=/usr/bin/nano
export EDITOR=/usr/bin/nano
Reload bash, and then push Esc to go into normal mode.
Type v, and nano should load. You can now enter your multiline command into nano. When you save and exit, the multiline command will be executed.
For zsh, the following lines in your rc may do it. I stole the last three lines from this answer and tested it on my zsh.
bindkey -v
autoload -U edit-command-line
zle -N edit-command-line
bindkey -M vicmd v edit-command-line
Actually this is possible.
While on that second line, pres Esc + X in order to execute a command,
and type push-line-or-edit (note that you can use Tab key for completion)
, then press return.
The prompt will change to a traditional one ditching your for> part from
continuation line, and you will have a new buffer filled with all your
previously typed lines, which of course now you can easily edit using well
known C-a or C-b keys.
I do not think this is possible, but here are other workarounds:
You can just write everything in one line. It is not easy to edit, but multiline strings are not easily editable either.
You can bind some key (e.g. <C-Enter> if you can tell your terminal not to output <C-m> in this case) to
function _-add-newline()
{
LBUFFER="$LBUFFER"$'\n'
}
zle -N add-newline _-add-newline
bindkey "\Ca" add-newline
. This way if you press <C-a> newline will appear in the buffer, but it will not trigger accept-line widget and previous line will still be editable. You can e.g. use left/right arrows to move to it.
If you type for x in y ; do<CR>echo foo<CR><C-c><Up> you will see for x in y ; do\necho foo in your buffer and all text will be editable. Note: you need <CR> to preserve last line (line aborted by <C-c> is not saved) and <C-c> to abort input; this variant will not work if you have already typed done (first <CR> will run the cycle). In last case you may discard last line with <C-c> and retype it.
Theoretically you may override accept-line widget with a code that parses your input and determines whether you have written command completely and if not then it will just append \n to the buffer (like in the above function) and do not run original accept-line, otherwise original accept-line is run. This variant is much harder to implement though, so I am saying “theoretically”.

OS X Terminal text stacking on top of itself

I'm encountering a strange issue in the Terminal app in Mac OS X Lion. When I enter in a long line of text that should wrap to the next line when it reaches the edge of the Terminal window, it continues to type on top of the text from the line above it.
Here are some screenshots to help illustrate the issue:
Before my text reaches the window edge:
After the text reaches the window edge:
I've also supplied screenshots of my text and window settings in case those might be helpful.
Text settings:
Window settings:
Thanks in advance for any assistance offered. I've had this issue for a while and just never got around to it. It's now really becoming a pain in the ass when I get into things that require big grep commands and long path names.
PS1 environment variable determines what shell's prompt will look like. man bash gives full documentation on it. (There are actually several of them, for different modes).
There are number of files that may be setting it, usually one of ~/.profile, ~/.bashrc, /etc/profile or /etc/bashrc.
If you're going to have color codes or other control sequences inside it, you must wrap them with \[ and \] properly (and NOT wrap normal text), otherwise line editing may become messed up like in your case. I suggest resetting PS1 to the default value then carefully adding coloring back item by item.
For example:
PS1='\[\033[1m\033[32m\]\u#\h \w\[\033[0m\]\$ '
^^^^^^^^^^^^^^^ ^^^^^^^
Coloring commands are underlined. Note how they are surrounded with \[ \].
I have the same problem, i found if you change
Advanced > Emulation > Declare terminal as: ANSI.
This solves colored PS1 problem. With Mac Terminal
BUT creates a strange behavior:
I found a solution to my problem with #koiyu answer.
https://apple.stackexchange.com/questions/37001/strange-behavior-in-terminal-with-custom-bash-profile/37036#37036
I used to have the same issue due to incorrectly using color codes. Here is my PS1 which solved the issue. Also if you use GIT, then this will be also helpful to show git branch you are working on and if your working tree is dirty or not. Put this in your .profile or .bash_profile
# Git branch in prompt.
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
parse_git_dirty() {
st=$(git status 2>/dev/null | tail -n 1)
if [[ $st == "" ]]; then
echo ''
elif [[ $st == "nothing to commit (working directory clean)" ]]; then
echo ''
elif [[ $st == 'nothing added to commit but untracked files present (use "git add" to track)' ]]; then
echo '?'
else
echo '*'
fi
}
# coloring the terminal comman line
SB_GREEN="\[\033[1;32m\]"
SB_BLUE="\[\033[1;34m\]"
SB_RED="\[\033[1;31m\]"
SB_NOCOLOR="\[\033[0m\]"
export PS1="$SB_GREEN\u#\h$SB_NOCOLOR: $SB_BLUE\w$SB_GREEN\$(parse_git_branch)$SB_RED\$(parse_git_dirty)$SB_NOCOLOR $ "
Hope this helps.
With the guidance of hamstergene I was able to figure out how to make it play nice. Using this Geek Stuff guide and this It's Me Tommy tutorial, I was able to define how I wanted my PS1 text to display. Changing this to something much more simplified eliminated the weird overlapping text issue I was running into.
Before:
After:
I simply edited my .bash_profile and added the following line:
export PS1="[\u#\h] > ";
Then I went and changed the window colors for good measure because I can.
The original issue was that there was a new line in the PS1 (FYI for anybody running into this)
Typically its improperly escaped color codes, but if its not that its that you have a new line in your ps1
As others have said, you have to properly wrap your color commands in escaped square brackets. However, for me, this makes the string really, really confusing to look at!
As such, here's a trick I use to always get it right and also make it much more readable.
I first create a shell function called setColor like so...
setColor(){
echo "\[\033[${1}m\]"
}
Then I use it like this...
PS1="$(setColor 92)\u$(setColor 37):$(setColor 96)\w $(setColor)\$ "
That's the same as writing this...
\[\033[92m\]\u\[\033[37m\]:\[\033[96m\]\w \[\033[m\]$
...but as you can see, the former is much clearer and also guarantees everything's properly escaped.
Note, you can specify multiple colors too by using the ; character. The only thing is you have to explicitly escape it, so 92;41 becomes 92\;41, like so...
PS1="$(setColor 92\;41)\u$(setColor 37):$(setColor 96)\w $(setColor)\$ "
Again, still easier to read than this...
\[\033[92;41m\]\u\[\033[37m\]:\[\033[96m\]\w \[\033[m\]$
You can take this a step further by defining constants for the colors, or even 'wrapper' functions with the color names you use most, so you can write this...
PS1="$(setRed)\u$(setBlue):$(setGreen)\w $(resetColor)\$ "
Hope this helps!

ZSH auto-complete screws up command name

When I start doing tab auto-complete of a command, it keeps what I initally typed next to it and the command becomes unreadable. In the example below, I typed 'git che' and hit tab. Once I select 'checkout' the command prompt becomes 'git che git checkout'. The command still works and in my history it stores 'git checkout'. But its pretty annoying visually. Is there anyway to change this behavior. I tried this in 2 different terminal emulators, so I can confirm its ZSH and not the emulator. Thanks
Screenshot
EDIT:
echo $ZSH_VERSION
4.3.10
It doesnt seem to happen with zsh -f. Though its hard to tell since the only autocomplete that works is directories. I'm using 'oh-my-zsh' with this custom theme:
autoload -U add-zsh-hook
add-zsh-hook chpwd do_ls_on_chdir
function do_ls_on_chdir() {
ls;
}
function dirStack(){
OUT='';
NUM=1;
for X in $(dirs | cut -d ' ' -f2-10); do
OUT="$OUT$1%B$NUM:%b$1$X ";
(( NUM=NUM+1 ))
done
echo $OUT;
}
ZSH_THEME_GIT_PROMPT_ADDED=""
ZSH_THEME_GIT_PROMPT_MODIFIED=""
ZSH_THEME_GIT_PROMPT_DELETED=""
ZSH_THEME_GIT_PROMPT_RENAMED=""
ZSH_THEME_GIT_PROMPT_UNMERGED=""
ZSH_THEME_GIT_PROMPT_UNTRACKED=""
ZSH_THEME_GIT_PROMPT_AHEAD="%{$fg_bold[yellow]%}↑"
ZSH_THEME_GIT_PROMPT_PREFIX=""
ZSH_THEME_GIT_PROMPT_SUFFIX=""
ZSH_THEME_GIT_PROMPT_DIRTY=" %{$fg_bold[red]%}✗"
ZSH_THEME_GIT_PROMPT_CLEAN=" %{$fg_bold[green]%}✔"
local user_color='blue'
local back="${BG[237]}"
test $UID -eq 0 && user_color='red'
PROMPT='$(dirStack $back)
$back%B%!%b$back %{$fg_bold[$user_color]%}%~%{$reset_color%}'\
'$back $(git_prompt_status)%{$reset_color%}'\
'$back%{$fg_bold[magenta]%}$(git_prompt_info)%{$reset_color%}'\
'$back$(git_prompt_ahead)$reset_color'\
'$back%(!.#.>)$reset_color '
PROMPT2='%{$fg[red]%}%_ %{$reset_color%}'
PROMPT3='%{$fg[red]%}... %{$reset_color%}'
RPROMPT='%(?..%{$fg_bold[red]%}exit %?%{$reset_color%})'\
' %{$FG[186]%}(%D %*)%{$reset_color%}'
SOLUTION:
NOTE: stackoverflow wont let me answer my own question since I asked it within the past 8 hours. I dont feel like waiting.
So I figured it out. It turns out I wasnt properly escaping the ANSI color codes (I think). Everywhere I had $reset_color in my PROMPT variable, I changed that to %{$reset_color%} and it fixed it.
So I figured it out. It turns out I wasnt properly escaping the ANSI color codes (I think). Everywhere I had $reset_color in my PROMPT variable, I changed that to %{$reset_color%} and it fixed it.
I only discovered this link tonight, after messing with my prompt - I'd always wondered why the ZSH prompt examples seemed so needlessly complex.
When you set up the colors in your zsh prompt, you should escape things with %{ [...] %}, so that 'the shell knows there is no output from these sequences and the cursor hasn't moved'.
If you don't escape this, the shell believes that your cursor has moved (even though it hasn't). This leads to messed up prompts, and rather annoying visual effects when you use tab-completion etc.
Here's some screenshots without escaping the reset-color prompt sequence (PR_NO_COLOUR="%{$terminfo[sgr0]%}", in my prompt settings). As we can see, the cursor starts in the wrong place:
It should be here:
And after trying tab-completion without escaping, the prompt is all confused about where the text is, and where the cursor should be placed:
(The cursor should be placed at the end of the directory, not halfway through).
So the prompt sequences look like this:
PS1="%{$fg[red]%}%n%{$reset_color%}#%{$fg[blue]%}%m %{$fg[yellow]%}%~ %{$reset_color%}%% "
because everything has to be escaped nicely inside %{...%} pairs.

Going backwards in a bash prompt

I'd like to have a blank line after my bash prompt and before the output on my Mac. It should look like this would:
echo; ls
Can I add a newline to my bash prompt and then go back up one line to wait for user input? Is there something obvious I'm missing?
I know this is old but for someone like me who came across this while googling for it. This is how you do this...
It's actually pretty simple!
Check out this link --> Cursor Movement
Basically to move up N number of lines:
echo -e "\033[<N>A HELLO WORLD\n"
Just change the "< N >" to however many lines you want to go back...
For instance, to move up 5 lines it would be "/033[5A"
To my knowledge this is not possible unless you delve into more low-level stuff like full-screen emulators like curses.
This is a bit of a stab in the dark, but you may be able to use VT102 terminal codes to control the cursor without having to use Curses. The relevant VT102 commands that you'd be interested in all consist of sending ESC, then [, then the specific command parameters.
For instance, to move the cursor up one line, one needs to output:
ESC [ 1 A
0x1B 0x5B 0x31 0x41
Be warned that the VT102 documentation generally uses octal, so keep an ascii table handy if you're using hex.
All of this advice is given without having tested it -- I don't know if VT102 commands can be embedded into your bash prompt, but I thought it might be worth a shot.
Edit: Yeah -- looks like a lot of people use VT102 formatting codes in their bash prompts. To translate my above example into something Bash would recognize, putting:
\e[1A
into your prompt should move the cursor up one line.
This is very possible. If your bash has C-v set as the readline quoted-insert command, you can simply add the following to your ~/.inputrc:
RETURN: "\C-e\C-v\n\C-v\n\n"
This wil make bash (readline, actually) insert two verbatim newlines before a regular interpreted newline. By default, only one is inserted, which is what causes output to start on the line after the prompt.
You can test if C-v is set to quoted-insert by typing it in bash (that's Ctrl+V) followed by e.g. an up arrow. This should print ^[[A or something similar. If it doesn't, you can bind it in ~/.inputrc too:
C-v: quoted-insert
RETURN: "\C-e\C-v\n\C-v\n\n"
~/.inputrc can be created if it doesn't exist. The changes will not take effect in running bashes unless you issue a readline re-read-init-file command (by default on C-x C-r). Be careful though. If you do something wrong, enter will no longer issue commands, and fixing your mistake could prove to be difficult. If you should do something wrong, C-o will by default also accept the line.
Adding a newline followed by moving the cursor back to the regular prompt (like you described) is possible, but will not have the effect you intend. The newline you inserted would simply be overwritten by the application output, since you moved the cursor back in front of it.
This works:
trap echo DEBUG
It doesn't add an extra newline if you hit return at an empty prompt.
The command above will cause a newline to be output for every member of a pipeline or multi-command line such as:
$ echo foo; echo bar
\n
foo
\n
bar
To prevent that so that only one extra newline is output before all command output:
PROMPT_COMMAND='_nl=true'; trap -- '$_nl && [[ $BASH_COMMAND != $PROMPT_COMMAND ]] && echo; _nl=false' DEBUG
The DEBUG trap is performed before each command so before the first command it checks to see if the flag is true and, if so, outputs a newline. Then it sets the flag to false so each command afterwards on the line doesn't trigger an extra newline.
The contents of $PROMPT_COMMAND are executed before the prompt is output so the flag is set to true - ready for the next cycle.
Because pressing enter on an empty command line still triggers the execution of the contents of $PROMPT_COMMAND the test in the trap also checks for those contents as the current command and doesn't perform the echo if they match.
I believe (but haven't tried) if you put '\n\b' in the prompt string it would do that.
In general, if you want to find out the codes to do anything a terminal can do, read the terminfo man page.
In this case, the cursor up one line code can be determined by:
tput cuu1
If you redirect the tput output to a file, you can see what control characters are used.
Bash also supports the PROMPT_COMMAND variable, allowing you to run arbitrary commands before each prompt is issued.

Resources