Bash - Update terminal title by running a second c

2020-02-17 09:21发布

On my terminal in Ubuntu, I often run programs which keep running for a long time. And since there are a lot of these programs, I keep forgetting which terminal is for which program, unless I tab through all of those. So I wanted to find a way to update my terminal title to the program name, whenever I run a command. I don't want to do it manually.

I use gnome-terminal, but answer shouldn't really depend on that. Basically, If I'm able to run a second command, then I can simply use gconftool command to update the title. So I was hoping to find a way to capture the command in bash and update the title after every command. How do I do that?

8条回答
劫难
2楼-- · 2020-02-17 09:54

I have tested three method, all is OK, use any one for your pleasure.

export PROMPT_COMMAND='echo -ne "\033]2;$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//g")\007"'

trap 'echo -ne "\033]2;$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//g")\007"' DEBUG

trap 'echo -ne "\e]0;"; echo -n $BASH_COMMAND; echo -ne "\a"' DEBUG

please note if use $BASH_COMMAND, it don't recognize bash alias, and use PROMPT_COMMAND show finished command, but use trap show running command.

查看更多
做自己的国王
3楼-- · 2020-02-17 09:58

I'm doing something like this, to show my pwd in the title, which could be modified to do whatever you want to do with the title:

function title { echo -en "\033]2;$1\007"; }
function cd { dir=$1; if [ -z "$dir" ]; then dir=~; fi; builtin cd "$dir" && title `pwd`; }

I just threw this in my ~/.bash_aliases.

Update

I ran into strange bugs with my original answer. I ended up picking apart the default Ubuntu PS1 and breaking it into parts only to realize one of the parts was the title:

# simple prompt
COLOR_YELLOW_BOLD="\[\033[1;33m\]"
COLOR_DEFAULT="\[\033[0m\]"
TITLE="\[\e]0;\u@\h:\w\a\]"
PROMPT="\w\n$ "
HUH="${debian_chroot:+($debian_chroot)}"
PS1="${COLOR_YELLOW_BOLD}${TITLE}${HUH}${PROMPT}${COLOR_DEFAULT}"

Without breaking into variables, it would look like this:

PS1="\[\033[1;33m\]\[\e]0;\u@\h:\w\a\]${debian_chroot:+($debian_chroot)}\w\n$ \[\033[0m\]"
查看更多
爷的心禁止访问
4楼-- · 2020-02-17 10:01

Try this:

trap 'echo -ne "\033]2;$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//g")\007"' DEBUG

Thanks to the history 1 it works even with complicated expressions like:

true && (false); echo $? | cat

For which approaches relying on $BASH_COMMAND or $@ fail. For example simon's displays:

true | echo $? | cat

Thanks to Gilles and simon for providing inspiration.

查看更多
Bombasti
5楼-- · 2020-02-17 10:01

The OP asked for bash, but others might be interested to learn that (as mentioned above) this is indeed a lot easier using the zsh shell. Example:

# Set window title to command just before running it.
preexec() { printf "\x1b]0;%s\x07" "$1"; }

# Set window title to current working directory after returning from a command.
precmd() { printf "\x1b]0;%s\x07" "$PWD" }

In preexec, $1 contains the command as typed (requires shell history to be enabled, which seems to be a fair assumption), $2 the expanded command (shell aliases etc.) and $3 the "very expanded" command (shell function bodies). (more)

查看更多
混吃等死
6楼-- · 2020-02-17 10:05

I have some answers for you :) You're right that it shouldn't matter that you're using gnome-terminal, but it does matter what command shell you're using. This is a lot easier in zsh, but in what follows I'm going to assume you're using bash, and that it's a fairly recent version (> 3.1).

First of all:

Which environment variable would contain the current 'command'?

There is an environment variable which has more-or-less what you want - $BASH_COMMAND. There's only one small hitch, which is that it will only show you the last command in a pipe. I'm not 100% sure what it will do with combinations of subshells, either :)

So I was hoping to find a way to capture the command in bash and update the title after every command.

I've been thinking about this, and now that I understand what you want to do, I realized the real problem is that you need to update the title before every command. This means that the $PROMPT_COMMAND and $PS1 environment variables are out as possible solutions, since they're only executed after the command returns.

In bash, the only way I can think of to achieve what you want is to (ab)use the DEBUG SIGNAL. So here's a solution -- stick this at the end of your .bashrc:

trap 'printf "\033]0;%s\007" "${BASH_COMMAND//[^[:print:]]/}"' DEBUG

To get around the problem with pipes, I've been messing around with this:

function settitle () {
    export PREV_COMMAND=${PREV_COMMAND}${@}
    printf "\033]0;%s\007" "${BASH_COMMAND//[^[:print:]]/}"
    export PREV_COMMAND=${PREV_COMMAND}' | '
}

export PROMPT_COMMAND=${PROMPT_COMMAND}';export PREV_COMMAND=""'

trap 'settitle "$BASH_COMMAND"' DEBUG

but I don't promise it's perfect!

查看更多
7楼-- · 2020-02-17 10:07

You can set up bash such that it sends a certain escape sequence to the terminal every time it starts an external program. If you use the escape sequence that terminals use to update their titles, your problem should be solved.

I have used that before, so I know it is possible. but I cannot remember it off the top of my head and do not have time to research the details right now, though.

查看更多
登录 后发表回答