PuTTY: Linux window - How to update the window title during a function? - linux

I’m accessing a Linux machine from a Windows 10 PC via PuTTY. I’ve set the PuTTY (Bash) window title to ‘$PWD’ by setting $PS1 as below:
PS1=\[\033]0;\w\007\]\[\033[1;33m\][\w]$\[\033[0m\]
This works well – whenever I change the directory in the shell, the title updates straight away:
However, if I change directory in a function (as below) the title doesn’t update until after the function completes:
function func() {
cd /share/testing_area/runtests ;
python Script.py;
}
Is there a way to get the title to update during the script?
ANSWER: Final version of the script:
function func() {
cd /share/testing_area/runtests
export PS1="\[\e[1;33m\][\w]$\[\e[0m\]" # Remove title spec from $PS1
echo -ne "\e]2;$PWD\a" # Set title to current values (uses $PWD as \w doesn't work for echo
python Script.py;
export PS1="\[\033]0;\w\007\]\[\033[1;33m\][\w]$\[\033[0m\]" # Re-add title spec to $PS1
}

You are changing the title by using PuTTY’s automatic title from the prompt. Unfortunately, the prompt will usually take effect once your prompt is visible again, which means not before your function or script ends.
If you want to change the title dynamically I would recommend this solution instead.

Related

Linux shell (Bash/Z shell) - change background color when under a specific directory

I would like to change the background color of a shell (Z shell, but Bash will do as well) every time I go under a specific directory. For example, I would like to change the background color every time I am in /mnt/data to say red and change it back to normal if I go out of /mnt/data/...
To change the background and preserve my current prompt, I do:
export PS1="$PS1 %{$'\e[0;41m'%}"
I am not sure how to hook this up so that it is evaluated (wrapped in an if statement) every time I change working directory.
The trick is to use the command substitution in PS1. The following kind of works for me in Bash:
PS1='$(if [[ $PWD == /mnt/data* ]] ; then printf "\[\e[0;41m\]" ; else printf "\[\e[m\]" ; fi) %'
By "kind of" I mean the fact that the behaviour on the command line immediately after changing to/from the directory is a bit weird (e.g., the background changes after you press Backspace).
You can also use the PROMPT_COMMAND shell variable which is more suitable for code than the prompt itself:
PROMPT_COMMAND='if [[ $PWD == /mnt/data* ]] ; then printf "\e[0;41m" ; else printf "\e[m" ; fi'
It's cleaner to keep the code in a function with all the proper indentation, and just call the function from the variable:
colour_mnt_data () {
if [[ $PWD == /mnt/data* ]] ; then
printf '\e[0;41m'
else
printf '\e[m'
fi
}
PROMPT_COMMAND='colour_mnt_data'
Answer for zsh (although the second part can be adapted to bash):
This is a two-part problem:
Acting on directory changes: For zsh you can just use the chpwd hook function. chpwd as well as any function listed in the chpwd_functions array are called each time the current working directory is changed.
So, if you want to react to certain directories you can use something like this
# load helper function to manipulate hook arrays
autoload -Uz add-zsh-hook
# define hook function, decide on action based on $PWD, the new pwd.
chback_on_chdir () {
case $PWD in
/mnt/data/* )
# change background, when entering subdirectories of "/mnt/data"
;;
/home )
# change background, when entering exactly "/home"
;;
/usr | /usr/* )
# change background, when entering "/usr" or a subdirectory thereof
;;
* )
# change background, when entering any other directory
;;
esac
}
# add chback_on_chdir to chpwd_functions
add-zsh-hook chpwd chback_on_chdir
Changing the background color: There are actually two ways to change the background color.
You can change the background for the following printed characters within the colors available within the terminal (which is, what you do in your example). In zsh this could be done like this (shortened example for chdir hook):
# allow for parameter substitution in prompts
setopt PROMPT_SUBST
# add string `$COLOR` to $PS1.
# Note the `\` before `${COLOR}`, which prevents immediate evaluation.
# `${COLOR}` will be substituted each time the prompt is printed
PS1="$PS1\${COLOR}"
chpwd () {
case $PWD in
/mnt/data/* )
# set background color to red
COLOR='%K{red}'
;;
* )
# reset background color to default
COLOR='%k'
# could also be just an empty string
#COLOR=''
# or unset
#unset COLOR
;;
esac
}
In some (many?) terminals you can also redefine the default background color. This will actually change the background color everywhere, even on already printed text and "unprinted" locations. This can be done by utilizing XTerm Control Sequences, which - despite their name - work in other terminal emulatores, too. (I tested successfully with xterm, urxvt, gnome-terminal and termite). The control sequence in question is
ESC]11;<color>ST
where ESC is the escape character \e, <color> is a color specification (e.g. red, #ff0000, rgb:ff/00/00, rgbi:1/0/0 - what actually works might depend on the terminal) and ST is the string terminator \e\\ (ESC\). You can send it to the terminal with
printf "\e]11;red\e\\"
You can reset the color to the configured default with the control sequence
ESC]111ST
using the command
printf "\e]111\e\\"
So, if you usually have a black background and want to tint it slightly red when entering /mnt/data or a directory below it, you can use:
chpwd () {
case $PWD in
/mnt/data | /mnt/data/* )
# set background color to a dark red
printf "\e]11;#1f0000\e\\"
;;
* )
# reset the background color to configured default
printf "\e]111\e\\"
;;
esac
}
Note: I found that it does not seem to work on urxvt, if transparency is enabled.
It is possible to retrieve the current value by replacing the color specification with ?:
printf "\e]11;?\e\\" ; sleep 1
The sleep 1 is needed so that the output is not immediately overwritten by the prompt.
You will need to write a script file with functions that you can call to determine what your PS1 should be because of the directory that you are in.
Then, you source this script file in your .bashrc and set your PS1 so that it calls the function from your script file to set its value.
. ~/.myCleverPS1
export PS1='$PS1 $(myCleverPS1func " (%s)") $ '
An example you can look at is the git-completion script which adds the name of the current branch to the prompt whenever you are in a git repo directory (and can optionally colorize too).
See as example: https://github.com/git/git/tree/master/contrib/completion

Turn off terminal entry line prefix/header

How do I fix this? I don't want to change my server name I just want to customize the text here (no server name, still shows path/user). Also what's this section of the terminal window called?
The Terminal Entry line prefix is called the shell prompt.
You can generally find the current config by typing
echo $PS1
That returned this for me: [\e]0;\u#^C\w\a]${debian_chroot:+($debian_chroot)}\u#\h:\w\$
So I was able to remove the "#\h" in both locations and get the desired tag.
export PS1="\[\e]0;\u: \w\a\]${debian_chroot:+($debian_chroot)}\u:\w\$ "
leaving me with "root:/kliq$'

gnuplot script name OR bash $0 alternative for gnuplot

How to programmatically get the name of current gnuplot script? I know that I can call gnuplot script from bash and get it file name but I am wondering if it is possible from inside gnuplot. My goal is to make something like:
date=system("date +%F_%T | sed 's/:/-/g'")
my_name=$0 # THIS IS HOW TO DO IT IN BASH
set term png
set output my_name.date.".png"
I've tried:
my_name=system("cat /proc/$$/cmdline")
but it returned sh instead of script name
Not quite an answer to your question, but this might help with what you want to do:
You can leave my_name unset in the script, and set it either inside gnuplot, just before you load the script (where you need to know the script name anyway):
my_name=...
load(my_name)
or set it when you invoke gnuplot from the shell:
$ gnuplot -e "my_name=${FILE}" ${FILE}
A few more things:
date=system("date +%F_%T | sed 's/:/-/g'")
can be replaced with
date=system("date +%F_%H-%M-%S")
(which is shorter and doesn't need to be parsed through sed) or without any forking at all:
date=strftime("%F_%H-%M-%S",time(0.0))
Using gnuplot version 5 you have access to the file called with load via the variable ARG0
Consider the script test.gp which contains only
print ARG0
Now, calling this with
gnuplot -e "load 'test.gp'"
prints you test.gp on the screen. With earlier versions you don't have access to a similar variable (also not when using call). For earlier versions you must stick to one of the solutions given by #chw21

Create window into screen

Is there a way to list all window names and depending on the result, creating a new window with a specific name into this (running) session.
How to create a new screen session with assigned window names is documented in the man pages, but i could find information about a solution to the problem above.
From outside the screen session, I don't think so.
But if you are starting from inside, in one of the windows of the right screen session, then yes:
for window_name in foo bar baz quux ; do ## ...
screen -t $window_name
done
You can even get fancy and run some initial commands in each window! This snipped of copy-paste bash helps me get back to work quickly after a reboot. Once I've started the screen session:
for n in $(seq 1 8) ; do ## ...
screen -t proj_$n bash -c "cd /src/foo/proj_$n*/ ;"\
' eval `set_proj_env_vars.sh` ; svn status ; make clean ; make ;'\
' exec bash --login'
done
...and as a great side effect the screen windows are numbered for the various checkouts, where each one can be working on a different bug/feature. Overkill? Totally! But it's a fun hack.

current directory doesn't appear in title bar when running under screen

My xterm $prompt variable in my .tcshrc is:
set prompt="%{\033]0;%m:%~\007%}%{^[[;37;1m%}%B%{^[[;34;1m%}%m%{^[[;34;1m%}:%b%c%# "
The highlighted part above (%{\033]0;%m:%~\007%}) puts the hostname (%m) and the current directory (%~) in the title bar. (At least I think that that's what puts it in the title bar; it's been a while since I fiddled with this prompt).
When I run screen, however, the current directory stops getting updated when I change directories.
My questions:
How can I make this prompt work in screen?
Is there a better way to display the current directory in the title bar?
I am running linux with xterm and tcsh.
I think there is no direct way, because of the way screen works. However screen can display its own status bar, that you can define in .screenrc. Here's mine for instance :
hardstatus alwayslastline
hardstatus string '%{= kG}[ %{G}%H %{g}][%=%{=kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B}%Y-%m-%d %{W}%c %{g}]'
Firstly, to make it work you must check where exactly is the line with set prompt=blah-blah in your .tcshrc. For example, the code below that perfectly works in plain xterm would not work under screen in xterm:
switch ($TERM)
case "xterm*":
set prompt="%{\033]0;${HOME:t}#%m:%l:%c08\007%}%{\033[36m%}%l:%c02%#%{\033[0m%} "
# update xterm title to display current cmd in it
alias postcmd 'echo -n "\033]0;${HOME:t}#`hostname`:${tty} \!#:q\007"'
...
because screen by default sets $TERM variable to screen and not xterm! So you must add:
case "screen":
# lame, but prevents an error in screen after 'su - root'
if (! $?WINDOW) setenv WINDOW 1
set prompt="%{\033]0;${HOME:t}#%m:${WINDOW}:%c08\007%}%{\033[36m%}%c02%#%{\033[0m%} "
alias postcmd 'echo -n "\033]0;${HOME:t}#`hostname`:${WINDOW} \!#:q\007"'
...
Secondly, make sure yo have this line in ~/.screenrc:
termcapinfo xterm* 'hs:ts=\E]2;:fs=\007:ds=\E]2;\007'

Resources