Dynamic window title in Urxvt with Zsh? - terminal

How can I set the window title of Urxvt to the currently running (interactive) command in Zsh shell?
For instance, if I am running journalctl, I want journalctl to be displayed as the window title. Currently the window title is just showing urxvt, which is fine if I am running no commands.

This is possible with the precmd and preexec hooks. I use this for my xterm. It might work unmodified. If not, the place to tweak is the escape sequence to set the terminal title, here ESC, ], 0, ;.
case $TERM in
(*xterm* | rxvt)
# Write some info to terminal title.
# This is seen when the shell prompts for input.
function precmd {
print -Pn "\e]0;zsh%L %(1j,%j job%(2j|s|); ,)%~\a"
}
# Write command and args to terminal title.
# This is seen while the shell waits for a command to complete.
function preexec {
printf "\033]0;%s\a" "$1"
}
;;
esac

Might be an overkilled solution but installing oh-my-zsh and using its default configuration gives me a dynamic window title. See the following screenshot as an example:

Related

Is there a way in bash -o vi mode to have the prompt indicate normal/command mode, etc

I use vi mode in bash all of the time. It would be really useful to see visually if I am in command mode or insert mode.
For example when I want to search the history, typing /my_search in either mode looks the same until I press Enter, and by then it's too late. I find myself pressing Esc much more than necessary just to make sure I'm in the right mode....
You can configure this in the .inputrc file that readline uses.
set show-mode-in-prompt
For me, this draws a + as the first character in insert mode, a : in normal mode, and no character in search mode.
(You can also enable vi mode in here using set editing-mode vi, which will enable it for all programs using readline, such as the python and ruby interpreters, instead of just bash).
I'm not sure you can do this in the prompt itself, but I think a cursor shape/color indicator is at least as useful.
The following setup gives a square, green, block cursor in normal mode, and a skinny, flat, gray underline cursor when in insert mode. There may be a way to do it in bash, but I have it working in Zsh, so I'll share this. It happens to be in URxvt, but should work in xterm, too. In ~/.zshrc:
# Modal cursor color for vi's insert/normal modes.
zle-keymap-select () {
if [ $KEYMAP = vicmd ]; then
echo -ne "\033]12;Green\007"
echo -ne "\033[2 q"
else
echo -ne "\033]12;Grey\007"
echo -ne "\033[4 q"
fi
}
zle -N zle-keymap-select
zle-line-init () {
zle -K viins
echo -ne "\033]12;Gray\007"
echo -ne "\033[4 q"
}
zle -N zle-line-init
Resources: https://bbs.archlinux.org/viewtopic.php?id=95078 AND https://unix.stackexchange.com/questions/115009/how-to-change-the-cursor-theme-in-cli
EDIT: I posted a comprehensive guide to getting this working in a combo of vim, zsh, tmux, and urxvt.

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.

emacs terminal bash (PS1) prompt duplicated

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.

Determining the type of terminal (classic Unix terminal vs graphical terminal)

I'm configuring my prompt (PS1) via .bashrc and found one issue with my current configuration: I am using a 256 color scheme. This is not compatible with the classical terminal (accessible via e.g. Ctrl+Alt+F2) but looks beautiful in graphical terminals such as gnome-terminal, terminator, etc.
So I have to change my prompt depending on the type of terminal. To do this, I need a condition for if clause to test the type of terminal. Do you know how to do this?
the TERM variable indicates the terminal type.
when running in an x-terminal, it is usually xterm (but can also be xterm-color-256 as Dmitry has hinted in his answer).
the following code checks whether the value of $TERM starts with xterm (and thus catches several cases):
case "$TERM" in
xterm*)
echo "running as an x-terminal"
;;
*)
echo "not running as an x-terminal"
;;
esac
echo $TERM would give you the terminal type
This should work:
if [ "$TERM" == "xterm-color-256" ]; then echo "YES"; fi
Another approach: look at the parent process of the current shell. If its "login", you're in a console
parent=$(ps --pid $(ps --pid $$ --no-headers --format ppid) --no-headers --format cmd)
if [[ $parent == login* ]]; then
echo console
PS1='plain> '
else
echo assume you can get away with more
PS1='fancy> '
fi
You could use the value of $TERM to decide if you have a color terminal or not, but this value could be modified. The question is where this environment variable is being set when a new terminal window is opened.
This would be in the .bashrc file. However, a word of warning:
The value of $TERM may be a lie. This is just an environment variable that's set. How it is set is determined by the terminal program (on the Mac, the Terminal.app can set the terminal to xterm, xterm-color, vt100, ansi, and several others..
The terminal could be a color terminal, but doesn't use ANSI color codes. You could be in trouble if you simply assume that a particular escape sequence gets you a particular color.
If your prompt is set in the .bashrc file, changing the value of $TERM won't change the prompt.
That said, I would probably do something like this:
case $TERM in
*color*) PS1=...;;
*) PS1=...;;
esac
This way, my terminal will be set to color if I said it was an xterm-color or xterm-256color.

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