emacs terminal bash (PS1) prompt duplicated - bash

This is a bit of a convoluted question, but here goes nothing!
I've recently updated my bash prompt to the nice version appearing in the last post of this thread: Bash: custom PS1 with nice working directory path.
The relevant bash code (from that thread post) is copied here:
# define the awk script using heredoc notation for easy modification
MYPSDIR_AWK=$(cat << 'EOF'
BEGIN { FS = OFS = "/" }
{
if (length($0) > 16 && NF > 4)
print $1,$2,".." NF-4 "..",$(NF-1),$NF
else
print $0
}
EOF
)
# my replacement for \w prompt expansion
export MYPSDIR='$(echo -n "${PWD/#$HOME/~}" | awk "$MYPSDIR_AWK")'
# the fancy colorized prompt: [0 user#host ~]%
# return code is in green, user#host is in bold/white
export PS1='[\[\033[1;32m\]$?\[\033[0;0m\] \[\033[0;1m\]\u#\h\[\033[0;0m\] $(eval "echo ${MYPSDIR}")]% '
# set x/ssh window title as well
export PROMPT_COMMAND='echo -ne "\033]0;${USER}#${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")\007"'
This prompt looks roughly like so (in non-emacs terminals):
[0 user#host ~/my_dir]%
Where the "0" above is green and the "user#host" is bold.
(Note that the "0" can be all sorts of numbers, and represents the return value of the last command.)
The issue I'm experiencing is specific to shells running within emacs (and it occurs for most variants of terminal-interaction within emacs: 'term', 'ansi-term', 'shell', and 'eshell').
The prompt appears twice (and slightly broken) in emacs terminals, like so:
0;user#host ~/my_dir[0 user#host ~/my_dir]%
The 'second' version of the prompt, starting from and including the "[" looks just fine.
It's the preceding text, which appears without any styling (i.e. no green and no bold).
So, emacs must be interpreting some portion of the prompt as input, and my guess is the color or bold escaped indicators attached to the "0" and "user#host" portions of the prompt?
Might anyone know how to tell emacs to interpret the escapes correctly?
Or, alternatively, how to modify the prompt-setting commands such that both emacs will not hate it and it'll still work in non-emacs terminals?
And maybe even another alternative: how to add a test for the terminal type ('eterm-color' within emacs) with a modified string that is emacs-friendly?

The error comes from the export PROMPT_COMMAND=... statement.
You can avoid this being read in your configuration, by checking whether you have a shell running inside emacs or not. Here the environment variable INSIDE_EMACS becomes handy. From the Emacs manual (Sect. 32.7):
Emacs sets the environment variable INSIDE_EMACS in the subshell to ‘version,comint’, where version is the Emacs version (e.g., ‘24.1’). Programs can check this variable to determine whether they are running inside an Emacs subshell
In your example, you want
export PROMPT_COMMAND='echo -ne "\033]0;${USER}#${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")\007" only being executed when you are not in emacs, otherwise you get this nasty "double prompt". The following conditional statement in your code will help.
if [ -z "$INSIDE_EMACS" ];
then
export PROMPT_COMMAND='echo -ne "\033]0;${USER}#${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")\007"'
else
export PROMPT_COMMAND=''
fi
It checks whether you are not inside emacs, and only then the PROMPT_COMMAND variable is set to your desired value.

The extra display is coming from the PROMPT_COMMAND variable's contents. emacs appears not to understand the OSC 0 title setting xterm escape sequence and so prints out the output.

Related

Adding to $PS1 variable on Git Bash for Windows using ~/.bash_profile causes an issue with __git_ps1

So I am trying to customize the PS1 value to add a check mark or x to the prompt depending on the result of the previous command. Surprisingly I got that part to work fine.
However, it has broken the part of the prompt that shows the Git branch when viewing a Git repository.
Here is the previous PS1 value:
user#PC MINGW64 ~/Git
$ echo $PS1
\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$
and here is the new ~/.bash_profile script that breaks it:
function nonzero_return() {
RETVAL=$?
if [[ $RETVAL -ne 0 ]]
then
echo "❌ ($RETVAL)"
else
echo "✅"
fi
}
export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$"
Here is an example of the old prompt versus the new one:
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core (dist-amd64)
$
✅
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core
$
❌ (127)
user#PC MINGW64 ~/Git/docker-brew-ubuntu-core
$
SOLUTION
Thanks to #davlet, #joanis, and #torek for helping me resolve this issue. I also used some other suggestions from them to edit my PS1 value even further into a place that I really liked. If anyone is curious, here is the new ~/.bash_profile script:
function nonzero_return() {
local RETVAL=$?
if [[ $RETVAL -ne 0 ]]
then
echo "❌($RETVAL)"
else
echo "✅"
fi
}
PS1='\[\e]0;Git Bash: $MSYSTEM\007\]\n\[\e[31m\]`nonzero_return`\[\e[32m\] \u#\h \[\e[35m\]\w\[\e[36m\]`__git_ps1`\e[0m\n$'
I think you want to use single quotes when assigning to PS1, and loose the backslashes before backticks. Also PS1 shouldn’t be exported:
PS1='\[\e[31m\]`nonzero_return`[...]'
Also, make RETVAL local in your helper function, otherwise it may interfere with other scripts, ie:
local RETVAL=$?
I'm going to steal that prompt, I really like it!
You just need to escape the backticks around __git_ps1:
export PS1="\[\e[31m\]\`nonzero_return\`\[\e[m\]\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]\`__git_ps1\`\[\033[0m\]\n$"
The difference is
...\`__git_ps1\`...
instead of
...`__git_ps1`...
in the export statement.
A bit of an explanation
The way the PS1 variable works is that it gets evaluated each time the prompt is printed. That's why you can have functions in it like __git_ps1 or your nonzero_return do something different each time the prompt is printed.
When you use double quotes to define PS1, e.g.:
PS1="...`my_function`...$MYVAR..." # won't work
the shell applies normal double quote expansion right when PS1 is defined, which includes expanding that backtick'd function call, and filling in the current value of $MYVAR, storing only the results in PS1, which is not what you want.
If you escape the backticks, or, better yet, use single quotes as #davlet said, PS1 now contains those backticks and variables themselves, which get evaluation each time the prompt is printed.
You can give it a try: if you use single quotes and then change the value of $MSYSTEM, your prompt will reflect that change right away. The get the same effect with double quotes, you'd have to escape the $.
Getting rid of that newline
In the comments, you ask how to remove the newline after the checkmark or X. That newline comes from the \n you have in the middle of your PS1 definition. But I personally like that newline, because it means my prompt is preceded by a blank line, separating it more nicely from the output of the previous command, especially if that didn't output its own newline.
Here's how I would tweak your prompt:
PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]\n\[\e[31m\]`nonzero_return`\[\e[m\]\[\033[32m\]\u#\h \[\033[35m\]$MSYSTEM \[\033[33m\]\w\[\033[36m\]`__git_ps1`\[\033[0m\]\n$'
Details:
\[\033]0;$TITLEPREFIX:$PWD\007\] sets the Window's title bar
\n separates the prompt from the previous command's output
[\e[31m\]nonzero_return\[\e[m\] your return code function in bold red (note that the \[\e[m|] is superfluous here: it says reset the colour, but your next thing sets the colour again)
\[\033[32m\]\u#\h user#host in green
\[\033[35m\]$MSYSTEM the value of $MSYSTEM in purple
\[\033[33m\]\w current working directory in yellow
\[\033[36m\]`__git_ps1` is the Git status in Cyan
\[\033[0m\] resets the font
\n is the newline
$ is the "superuser indicator" which turns to # when you are the superuser.
More notes:
As #torek points out, \[ and \] are unnecessary before the final \n
You mix \e and \033: those are both escape sequences inserting an actual escape character in there. I prefer to use \e everywhere because I find it more legible.
This is a useful reference on bash prompts: https://wiki.archlinux.org/title/Bash/Prompt_customization

bash prompt: highlight command being entered

Entering a command on bash goes like this:
<Prompt $> <The Command I Entered>
<Output Of The Command>
I'm looking a way to make The Command I Entered bold.
It's easy to start bold from prompt with putting tput bold in PS1.
However the questions is, how to tput sgr0 it when Enter is pressed.
Can i use readline / bash magic to achieve this?
Pre Bash 4.4:
In bash 4.3.x (and maybe earlier), the "debug trap" is executed before a command from the command line is executed.
trap 'tput sgr0' DEBUG
But this has one disadvantage: It is executed before every simple command that is executed. So if you run:
$ echo Hello && echo World
The debug trap is called two times.
Then the following command will not work as expected:
tput setaf 1 ; echo "This is red"
The printed "This is red" will not be red.
See DEBUG trap and PROMPT_COMMAND in Bash and also the accepted answer to this question.
Bash 4.4
In Bash 4.4 the variable $PS0 was introduced. Here is a quote from the man page:
The value of this parameter is expanded (see PROMPTING below)
and displayed by interactive shells after reading a command
and before the command is executed.
So with bash 4.4 you could do the following:
PS0="\[$(tput sgr0)\]"
The \[\] are used to enclose unprintable characters (here the terminal control sequence to reset text attributes). I'm not sure if this is really needed for PS0, but it can't hurt. There is no visual difference in the shell output either way.
To extend Ralf's answer to make the command bold in bash 4.4+ requires setting PS1 and PS0 like so:
PS1="\[\e[32m\]\u#\h \t \W \\$\[\e[0;30;1m\] "
PS0="\[$(tput sgr0)\]"
Obviously you might not like my boring prompt, but it gives you a starting place with the command in bold. The \[\e[0;30;1m\] is setting the command to be displayed in black text and bold. Other color choices may suit you better.
I found this handy when using asciinema to capture examples for documentation. It reminds me of the O'Reilly style of including UNIX console examples with the command in bold.

bash prompt shell displayed differently in terminal and tty console

This is a portion of my ~/.bashrc:
prompt(){
local EXIT="$?" # return code
PS1=""
local red="\[\033[0;31m\]" # text colour
local purple="\[\033[0;35m\]" # text colour
local normal="\[\033[0m\]" # text colour
if [ $EXIT == 0 ]; then # $EXIT colour based upon its value
local return="${normal}${?}"
else
local return="${red}${?}${normal}"
fi
PS1+="${normal}[${purple}\\D{%-l:%M%P}${normal}]${return} \\[\\e]0; \
\\u#\\h: \\w\\a\\]${debian_chroot:+($debian_chroot)}\\u#\\h:\\w\\$ "
}
export PROMPT_COMMAND=prompt
This is my prompt shell in gnome-terminal (correctly displayed):
[5:01pm]0 user#host:~$
But when I switch to tty console, after I logged in, this is displayed:
[5:05pm]0 ;user#host: ~user#host:~$
This happens with regular user, but also with root on the same notebook on the same operating system.
Colours are always correctly displayed, the only problem is with the way the prompt is displayed.
Sofware versions:
GNU bash, version 4.3.11(1)-release (i686-pc-linux-gnu),
Ubuntu Gnome 14.04.
Some explanation of the PS1 value:
[5:01pm] # current time
0 # return/exit code of the last command (0 can be any number;
# if return code has a non-zero value, it turns red)
PS – Currently in tty consoles, I need to source ~/.bashrc to be able to used all of my settings. (1) Where is located the tty console’s own .bashrc? (2) Or how to set it up to use the ~/.bashrc?
Solution of the different behaviour of prompt
As the accepted answer suggests, in PS1 variable, there was a part which should be omitted, thus I just changed the last row of the function to
PS1+="${normal}[${purple}\\D{%-l:%M%P}${normal}]${return} \
${debian_chroot:+($debian_chroot)}\\u#\\h:\\w\\$ "
Solution of the Post Scriptum (PS)
tty consoles use ~/.bashrc_profile instead of ~/.bashrc, because (as #chepner said in comment below) the latter is sourced by GUI terminal emulator (for it usually starts a non-login interactive shell). tty console is an interactive shell.
My solution is to add the following to ~/.bash_profile:
. ~/.bashrc
You have \\[\\e]0; \\u#\\h: \\w\\a\\] and \\u#\\h:\\w\\$ in PS1.
The question is why is your terminal not showing that first set but your console is.
The answer, I believe, is that you have that first set enclosed in a \[...\] block which indicates that it is non-printing and takes up no space (this is why you need to enclose color codes in \[...\] to avoid the prompt being shorter than the terminal expects when the codes don't create visible characters.
This is causing gnome-terminal to discard everything (even visible characters) from the output/contents of the \[...\] block.
The console, presumably, is simply printing visible characters (and ignoring non-printing characters). (I wonder if this causes prompt size miscalculations or not.)
The solution here is to remove that first (seemingly unintentional) set of escapes.

What is the difference between PS1 and PROMPT_COMMAND?

While taking a look at this awesome thread I noticed that some examples use
PS1="Blah Blah Blah"
and some use
PROMPT_COMMAND="Blah Blah Blah"
(and some use both) when setting the prompt in a Bash shell. What is the difference between the two? A Stack Overflow search and even a bit of broader Google searching aren't getting me results, so even a link to the right place to look for the answer would be appreciated.
PROMPT_COMMAND can contain ordinary Bash statements whereas the PS1 variable can also contain the special characters, such as '\h' for hostname, in the variable.
For example, here is my Bash prompt that uses both PROMPT_COMMAND and PS1. The Bash code in PROMPT_COMMAND works out what Git branch you might be in and displays that at the prompt, along with the exit status of the last run process, hostname and basename of the pwd.
The variable RET stores the return value of the last executed program. This is convenient to see if there was an error and the error code of the last program I ran in the terminal. Note the outer ' surrounding the entire PROMPT_COMMAND expression. It includes PS1 so that this variable is reevaluated each time the PROMPT_COMMAND variable is evaluated.
PROMPT_COMMAND='RET=$?;\
BRANCH="";\
ERRMSG="";\
if [[ $RET != 0 ]]; then\
ERRMSG=" $RET";\
fi;\
if git branch &>/dev/null; then\
BRANCH=$(git branch 2>/dev/null | grep \* | cut -d " " -f 2);\
fi;
PS1="$GREEN\u#\h $BLUE\W $CYAN$BRANCH$RED$ERRMSG \$ $LIGHT_GRAY";'
Example output looks like this in a non-Git directory:
sashan#dhcp-au-122 Documents $ false
sashan#dhcp-au-122 Documents 1 $
And in a Git directory you see the branch name:
sashan#dhcp-au-122 rework mybranch $
Update
After reading the comments and Bob's answer, I think that writing it as he describes is better. It's more maintainable than what I originally wrote above, where the PS1 variable is set inside the PROMPT_COMMAND, which itself is a super complicated string that is evaluated at runtime by Bash.
It works, but it's more complicated than it needs to be. To be fair, I wrote that PROMPT_COMMAND for myself about 10 years ago and it worked and didn't think too much about it.
For those curious as to how I've amended my things, I've basically put the code for the PROMPT_COMMAND in a separate file (as Bob described) and then echo the string that I intend to be PS1:
GREEN="\[\033[0;32m\]"
CYAN="\[\033[0;36m\]"
RED="\[\033[0;31m\]"
PURPLE="\[\033[0;35m\]"
BROWN="\[\033[0;33m\]"
LIGHT_GRAY="\[\033[0;37m\]"
LIGHT_BLUE="\[\033[1;34m\]"
LIGHT_GREEN="\[\033[1;32m\]"
LIGHT_CYAN="\[\033[1;36m\]"
LIGHT_RED="\[\033[1;31m\]"
LIGHT_PURPLE="\[\033[1;35m\]"
YELLOW="\[\033[1;33m\]"
WHITE="\[\033[1;37m\]"
RESTORE="\[\033[0m\]" #0m restores to the terminal's default colour
if [ -z $SCHROOT_CHROOT_NAME ]; then
SCHROOT_CHROOT_NAME=" "
fi
BRANCH=""
ERRMSG=""
RET=$1
if [[ $RET != 0 ]]; then
ERRMSG=" $RET"
fi
if which git &>/dev/null; then
BRANCH=$(git branch 2>/dev/null | grep \* | cut -d " " -f 2)
else
BRANCH="(git not installed)"
fi
echo "${GREEN}\u#\h${SCHROOT_CHROOT_NAME}${BLUE}\w \
${CYAN}${BRANCH}${RED}${ERRMSG} \$ $RESTORE"
And in my .bashrc file:
function prompt_command {
RET=$?
export PS1=$(~/.bash_prompt_command $RET)
}
PROMPT_DIRTRIM=3
export PROMPT_COMMAND=prompt_command
From the GNU Bash documentation page (Bash Reference Manual):
PROMPT_COMMAND
If set, the value is interpreted as a command to execute before
the printing of each primary prompt ($PS1).
I never used it, but I could have used this back when I only had sh.
The difference is that PS1 is the actual prompt string used, and PROMPT_COMMAND is a command that is executed just before the prompt. If you want the simplest, most flexible way of building a prompt, try this:
Put this in your .bashrc file:
function prompt_command {
export PS1=$(~/bin/bash_prompt)
}
export PROMPT_COMMAND=prompt_command
Then write a script (Bash, Perl, or Ruby: your choice), and place it in file ~/bin/bash_prompt.
The script can use any information it likes to construct a prompt. This is much simpler, IMO, because you don't have to learn the somewhat baroque substitution language that was developed just for the PS1 variable.
You might think that you could do the same by simply setting PROMPT_COMMAND directly to ~/bin/bash_prompt, and setting PS1 to the empty string.
This at first appears to work, but you soon discover that the readline code expects PS1 to be set to the actual prompt, and when you scroll backwards in history, things get messed up as a result.
This workaround causes PS1 to always reflect the latest prompt (since the function sets the actual PS1 variable used by the invoking instance of the shell), and this makes readline and command history work fine.
From man bash:
PROMPT_COMMAND
If set, the value is executed as a command prior to issuing each primary prompt.
PS1
The value of this parameter is expanded (see PROMPTING below) and used as the primary prompt string. The default value is ''\s-\v\$ ''.
If you simply want to set the prompt string, using PS1 alone is enough:
PS1='user \u on host \h$ '
If you want to do something else just before printing the prompt, use PROMPT_COMMAND. For example, if you want to sync cached writes to disk, you can write:
PROMPT_COMMAND='sync'
Yeah, so to try to really nail this down:
PROMPT_COMMAND is a handy Bash convenience variable/function, but there is, strictly speaking, nothing that cannot also be done using PS1 alone, correct?
I mean, if one wants to set another variable with scope outside the prompt: depending on the shell, that variable would probably need to be declared first outside $PS1 or (worst case) one might have to get fancy with something waiting on a FIFO prior to calling $PS1 (and armed again at the end of $PS1); the \u \h might cause some trouble, particularly if you're using some fancy regex; but otherwise: one can accomplish anything PROMPT_COMMAND can by using command substitution within $PS1 (and, maybe in corner cases, explicit subshells)?
Right?
The difference is that
if you output an incomplete line from PROMPT_COMMAND, it will screw your Bash prompt
PS1 substitutes \H and friends
PROMPT_COMMAND runs its contents, and PS1 uses its contents as the prompt.
PS1 does variable expansion and command substitution at each prompt. There isn't any need to use PROMPT_COMMAND to assign a value to PS1 or to run arbitrary code. You can easily do export PS1='$(uuidgen) $RANDOM' once in file .bash_profile. Just use single quotes.
I spent so much time on this I just wanted to share what worked for me. I looked at a lot of the SO posts about PROMPT_COMMAND and PS1 and tried many combinations of single quotes, double quotes, calling functions... I could not get the prompt to update each time without printing control characters or the literal expanded but not processed prompt string, or without just setting PS1 in PROMPT_COMMAND as we are advised not to do. My problem was setting variables (colors) that contained control characters; these had to be hard-coded after the variable name in PS1. PROMPT_COMMAND is set to a function that sets variables and they are used (escaped) in a double-quoted PS1 string. This is for a powerline-style prompt that changes colors with each command.
icon1=#unicode powerline char like
#these: https://github.com/ryanoasis/powerline-extra-symbols#glyphs
icon2=#same
#array of ANSI colors. 2 for rgb mode then the rgb values
#then 'm' without '\]' control character. these are from
#the solarized theme https://ethanschoonover.com/solarized/
declare -a colors=(
"2;220;50;47m"
"2;203;75;22m"
"2;181;137;0m"
"2;133;153;0m"
"2;42;161;152m"
"2;38;139;210m"
"2;108;113;196m"
"2;211;54;130m"
"2;0;43;54m"
"2;7;54;66m"
"2;88;110;117m"
"2;101;123;131m"
"2;131;148;150m"
"2;147;161;161m"
)
#outside of vars set in PROMPT_COMMAND it's ok to have control chars
LEN=${#colors[#]}
BG="\[\e[48;"#set bg color
FG="\[\e[38;"#set fg color
TRANSP="1m\]"#transparency
BASE2="2;238;232;213m\]"#fg (text) color
myfunc(){
RAND=$(($RANDOM % $LEN))
COLOR1=${colors[$RAND]}
COLOR2=${colors[($RAND + 1) % $LEN]}
COLOR3=${colors[($RAND + 2) % $LEN]}
}
PROMPT_COMMAND=myfunc
#note double quotes and escaped COLOR vars followed by hard-coded '\]' control chars
PS1="$BG$TRANSP$FG\$COLOR1\]$icon1$BG\$COLOR1\]$FG$TRANSP$BG\$COLOR1\]$FG$BASE2
[username hard-coded in unicode] $BG\$COLOR2\]$FG\$COLOR1\]$icon2$BG\$COLOR2\]$FG$BASE2
\w $BG\$COLOR3\]$FG\$COLOR2\]$icon2$BG\$COLOR3\]$FG$BASE2 [more unicode]
\[\e[0m\]$FG\$COLOR3\]$icon2\[\e[0m\] "
That ought to get you going!

Set screen-title from shellscript

Is it possible to set the Screen Title using a shell script?
I thought about something like sending the key commands ctrl+A shift-A Name enter
I searched for about an hour on how to emulate keystrokes in an shell script, but didn't find the answer.
You can set the screen / xterm title using the following lines:
#!/bin/bash
mytitle="Some title"
echo -e '\033k'$mytitle'\033\\'
[UPDATE] - by request I'm also including the solution proposed by #Espo below:
Depending on your xterm version or your linux distribution the line above may or may not work and you can try the xterm-defaults:
#!/bin/bash
mytitle="Some title"
echo -e '\033]2;'$mytitle'\007'
For more on the details see: http://www.faqs.org/docs/Linux-mini/Xterm-Title.html#s3 or refer to the answer by #Espo below.
From http://www.faqs.org/docs/Linux-mini/Xterm-Title.html#s3
xterm escape sequences
Window and icon titles may be changed
in a running xterm by using XTerm
escape sequences. The following
sequences are useful in this respect:
ESC]0;stringBEL -- Set icon name and window title to string
ESC]1;stringBEL -- Set icon name to string
ESC]2;stringBEL -- Set window title to string
where ESC is the escape character
(\033), and BEL is the bell character
(\007).
Printing one of these sequences within
the xterm will cause the window or
icon title to be changed.
Note: these sequences apply to most
xterm derivatives, such as nxterm,
color-xterm and rxvt. Other terminal
types often use different escapes; see
the appendix for examples. For the
full list of xterm escape sequences
see the file ctlseq2.txt, which comes
with the xterm distribution, or
xterm.seq, which comes with the rxvt
distribution.
Printing the escape sequences
For information that is constant
throughout the lifetime of this shell,
such as host and username, it will
suffice to simply echo the escape
string in the shell rc file:
echo -n "\033]0;${USER}#${HOST}\007"
should produce a title like
username#hostname, assuming the shell
variables $USER and $HOST are set
correctly. The required options for
echo may vary by shell (see examples
below).
For information that may change during
the shell's lifetime, such as current
working directory, these escapes
really need to be applied every time
the prompt changes. This way the
string is updated with every command
you issue and can keep track of
information such as current working
directory, username, hostname, etc.
Some shells provide special functions
for this purpose, some don't and we
have to insert the title sequences
directly into the prompt string. This
is illustrated in the next section.
The following are other ways to script the renaming of screen titles:
Adding the following settings to .ssh/config sets the screen title automatically upon logging in to a system using SSH:
Host *
PermitLocalCommand yes
LocalCommand [ "$TERM" == 'screen' ] && echo -ne "\033k%h\033\\"
Instead of %h, which represents the hostname of the machine you are connecting with, you may use %n, which is the actual name / alias you used to connect to the machine.
NOTE: You need OpenSSH >= v5.1 to be able to use the Localhost %n and %h parameters. Check out 'man ssh_config' for more info on LocalCommand.
To automatically revert the title, back to that of the hostname of the localhost, after closing the SSH session, you can add an escape sequence to you prompt variable PS1 in .bashrc :
export PS1='you_favorite_PS1_here'
if [ "$TERM" == 'screen' ]; then
export PS1=${PS1}'\[\033k\h\033\\\]'
fi
These tricks are especially useful when using a .screenrc config that shows you in what screen 'tab' you are currently working. Add something like the following to .screenrc to get this working:
caption always "%{= kY}%-w%{= Yk}%n %t%{-}%+w%{ kG} %-= #%H - %LD %d %LM - %c"
Try the below commands, no need to edit any file or configuration like ~/.bashrc, Can be used at runtime.
Set static text as title: (My Title)
export PS1='\[\e]0;My Title\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
Set local/global variable as title: ($USER)
export PS1='\[\e]0;$USER\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
Set command output as title: (hostname)
export PS1='\[\e]0;`hostname`\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
Set to default (Revert back):
export PS1='\[\e]0;\u#\h: \w\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
set_screen_title ()
{
echo -ne "\ek$1\e\\"
}
You can also call screen and tell it to set a title:
screen -X title "new title"
If you're in a screen window, it will set that window's name. If you're not in screen, it will set the most recently opened window's name.
To add to Espo's answer, the xterm escape sequences can also be applied to the Bash PS1 variable
ESC]0;stringBEL -- Set icon name and window title to string
ESC]1;stringBEL -- Set icon name to string
ESC]2;stringBEL -- Set window title to string
Example
PS1='\e]0;string\a'
To enable automatic title updating when jumping around with ssh, add this to ~/.bashrc:
ssh() {
echo -n -e "\033k$1\033\\"
/usr/bin/ssh "$#"
echo -n -e "\033k`hostname -s`\033\\"
}
echo -n -e "\033k`hostname -s`\033\\"
See http://linuxepiphany.blogspot.com.ar/2010/05/good-screenrc-config-setup.html
# add the following in your ~/.bashrc or ~/.bash_profile
PROMPT_COMMAND='printf "\033]0;%s#%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
or even better copy the whole concept for customizing your bash configs between a lot of hosts from here
My solution to this problem was to create a bash script and add it to my ~/.bashrc file:
set-title() {
ORIG==$PS1
TITLE="\e];$#\a"
PS1=${ORIG}${TITLE}
}
Now when I'm in any bash shell session, I type "set-title desired_title" and it changes to "desired title".
This works for multiple versions of Ubuntu, currently on Kinetic 16.04
I got this solution from here. I was looking for it again, couldn't find it and thought I'd post it here for anyone interested.
I got this solution from experimenting with others, like #flurin-arner I started the #weston-ganger set-title(). I also used #imgx64 PROMPT_DIRTRIM suggestion. I'm also using #itseranga git branch prompt, though this has nothing to do with the question it does show what you can do with the prompt.
First as shown by weston and above
TITLE="\[\e]2;$*\a\]"
can be used to manually set the Terminal Title, "$*" is commandline input, but not what we want.
2nd as stated I'm also adding git branch to my prompt, again not part of the question.
export PROMPT_DIRTRIM=3
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u#\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ "
3rd, by experiment I copied the TITLE code above, set the $* to a fixed string and tried this:
see: \[\e]2;'SomeTitleString'\a\]
export PS1="\u#\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\]\[\e]2;'SomeTitleString'\a\] $ "
This had the desired effect! Ultimately, I wanted the base path as my title.
PS1 Params shows that \W is the base path so my solution is this:
export PS1="\u#\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\]\[\e]2;\W\a\] $ "
without the git branch:
export PS1="\u#\h \[\033[32m\]\w\[\033[33m\]\[\033[00m\]\[\e]2;\W\a\] $ "
resulting in a prompt with git-branch:
user#host ~/.../StudyJava (master) $
resulting in a prompt without parse_git_branch:
user#host ~/.../StudyJava $
where pwd gives
/home/user/somedir1/otherdir2/StudyJava
and Terminal Title
StudyJava
NOTE: From #seff above I am essentially replacing the "My Title" with "\W"
export PS1='\[\e]0;My Title\a\]${debian_chroot:+($debian_chroot)}\u#\h:\w\$ '
I tried this on Ubuntu 18.10 and it only worked with PROMPT_COMMAND in ~/.bashrc.
And if you override PROMPT_COMMAND, the behavior of the title changes slightly. I decided to change only if necessary:
t() {
TITLE="$#"
PROMPT_COMMAND='echo -ne "\033]0;${TITLE}\007"'
}
enter image description here

Resources