通过运行第二个命令来更新终端标题

时间:2021-09-23 03:06:22

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.

在我的Ubuntu终端上,我经常运行长时间运行的程序。因为有很多这样的程序,我总是忘记哪个终端是哪个程序的,除非我把所有这些都算进去。所以我想找到一种方法,在运行命令时,将终端标题更新为程序名。我不想手动操作。

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?

我使用gnome-terminal,但是答案不应该依赖于这个。基本上,如果我能够运行第二个命令,那么我可以使用gconftool命令来更新标题。所以我希望找到一种方法来捕获bash中的命令,并在每个命令之后更新标题。我该怎么做呢?

8 个解决方案

#1


20  

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).

我有一些答案:)你说得对,你使用的是gnome-terminal,但它确实与你使用的命令shell有关系。这在zsh中要容易得多,但是在接下来的内容中,我将假设您正在使用bash,并且它是一个相当新的版本(> 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 :)

有一个环境变量,它或多或少是您想要的- $BASH_COMMAND。这里只有一个小问题,那就是它只显示管道中的最后一个命令。我也不是100%确定它对子壳层的组合会有什么影响

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

所以我希望找到一种方法来捕获bash中的命令,并在每个命令之后更新标题。

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.

我一直在思考这个问题,现在我理解了您的意图,我意识到真正的问题是您需要在每个命令之前更新标题。这意味着$PROMPT_COMMAND和$PS1环境变量是尽可能的解决方案,因为它们只在命令返回后执行。

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:

在bash中,我能想到的实现您所需的惟一方法是(ab)使用调试信号。这里有一个解决方案,把这个贴在。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!

但我不保证它是完美的!

#2


12  

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:

感谢历史1,它甚至可以用复杂的表达,如:

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

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

使用$BASH_COMMAND或$@失败。例如西蒙的显示:

true | echo $? | cat

Thanks to Gilles and simon for providing inspiration.

感谢Gilles和simon提供的灵感。

#3


5  

I see what stoutie is trying to do, except it's a lot more work than needed. And doesn't cause all sorts of other potentially bad things that can occur as a result of redefining 'cd' and putting in all of that testing just to change directories. Bash has built in support for most of this.

我知道stoutie想做什么,只是工作量比需要的多。也不会因为重新定义“cd”而导致其他各种潜在的坏事情的发生,也不会因为改变目录而进行所有的测试。Bash已经构建了对其中大部分内容的支持。

You can put this in your .bashrc anywhere after you set your current PS1 prompt (this way it just prepends it)

在设置当前的PS1提示符后,可以将其放在.bashrc中。

# If this is an xterm set the titlebar to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

#4


1  

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:

我正在做这样的事情,在标题中显示我的pwd,它可以被修改成你想做的任何事情,标题:

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.

我只是把这个放到~/.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:

我用我最初的答案遇到了奇怪的虫子。最后我拆开了默认的Ubuntu PS1,把它分成了几个部分,结果发现其中一个部分是标题:

# 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\]"

#5


1  

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:

OP要求使用bash,但是其他人可能有兴趣了解(如上所述)使用zsh shell确实容易得多。例子:

# 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)

在preexec中,$1包含命令类型(需要启用shell历史,这似乎是一个合理的假设),$2扩展命令(shell别名等)和$3“非常扩展”命令(shell函数体)。(更多)

#6


0  

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.

您可以设置bash,使它在每次启动外部程序时向终端发送某个转义序列。如果您使用终端使用的转义序列来更新它们的标题,您的问题应该得到解决。

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.

我以前用过,所以我知道这是可能的。但我一时想不起来,也没有时间去研究细节。

#7


0  

Based on the the need to auto position putty windows I have modified my /etc/bash.bashrc file on a Debian/Ubuntu system. I have posted the full contents for completeness but the relevant bit to starts on the # Display command ... comment line.

由于需要自动定位腻子窗口,我修改了我的/etc/bash在Debian/Ubuntu系统上的bashrc文件。我已经发布了完整的内容,但是相关的位要从# Display命令开始……注释行。

# System-wide .bashrc file for interactive bash(1) shells.

# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

# Display command run in title which allows us to distinguish Kitty/Putty
# windows and re-position easily using AutoSizer window utility. Based on a
# post here: http://mg.pov.lt/blog/bash-prompt.html
case "$TERM" in
xterm*|rxvt*)
    # Show the currently running command in the terminal title:
    # http://www.davidpashley.com/articles/xterm-titles-with-bash.html
    show_command_in_title_bar()
    {
        case "$BASH_COMMAND" in
            *\033]0*)
                # The command is trying to set the title bar as well;
                # this is most likely the execution of $PROMPT_COMMAND.
                # In any case nested escapes confuse the terminal, so don't
                # output them.
                ;;
            *)
                echo -ne "\033]0;${USER}@${HOSTNAME}: ${BASH_COMMAND}\007"
                ;;
        esac
    }
    trap show_command_in_title_bar DEBUG
    ;;
*)
    ;;
esac

# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
#    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#    ;;
#*)
#    ;;
#esac

# enable bash completion in interactive shells
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

# if the command-not-found package is installed, use it
if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
        function command_not_found_handle {
                # check because c-n-f could've been removed in the meantime
                if [ -x /usr/lib/command-not-found ]; then
                   /usr/bin/python /usr/lib/command-not-found -- "$1"
                   return $?
                elif [ -x /usr/share/command-not-found/command-not-found ]; then
                   /usr/bin/python /usr/share/command-not-found/command-not-found -- "$1"
                   return $?
                else
                   printf "%s: command not found\n" "$1" >&2
                   return 127
                fi
        }
fi

#8


0  

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.

请注意,如果使用$BASH_COMMAND,它不识别bash别名,并使用PROMPT_COMMAND显示完成命令,但是使用trap show running命令。

#1


20  

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).

我有一些答案:)你说得对,你使用的是gnome-terminal,但它确实与你使用的命令shell有关系。这在zsh中要容易得多,但是在接下来的内容中,我将假设您正在使用bash,并且它是一个相当新的版本(> 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 :)

有一个环境变量,它或多或少是您想要的- $BASH_COMMAND。这里只有一个小问题,那就是它只显示管道中的最后一个命令。我也不是100%确定它对子壳层的组合会有什么影响

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

所以我希望找到一种方法来捕获bash中的命令,并在每个命令之后更新标题。

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.

我一直在思考这个问题,现在我理解了您的意图,我意识到真正的问题是您需要在每个命令之前更新标题。这意味着$PROMPT_COMMAND和$PS1环境变量是尽可能的解决方案,因为它们只在命令返回后执行。

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:

在bash中,我能想到的实现您所需的惟一方法是(ab)使用调试信号。这里有一个解决方案,把这个贴在。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!

但我不保证它是完美的!

#2


12  

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:

感谢历史1,它甚至可以用复杂的表达,如:

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

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

使用$BASH_COMMAND或$@失败。例如西蒙的显示:

true | echo $? | cat

Thanks to Gilles and simon for providing inspiration.

感谢Gilles和simon提供的灵感。

#3


5  

I see what stoutie is trying to do, except it's a lot more work than needed. And doesn't cause all sorts of other potentially bad things that can occur as a result of redefining 'cd' and putting in all of that testing just to change directories. Bash has built in support for most of this.

我知道stoutie想做什么,只是工作量比需要的多。也不会因为重新定义“cd”而导致其他各种潜在的坏事情的发生,也不会因为改变目录而进行所有的测试。Bash已经构建了对其中大部分内容的支持。

You can put this in your .bashrc anywhere after you set your current PS1 prompt (this way it just prepends it)

在设置当前的PS1提示符后,可以将其放在.bashrc中。

# If this is an xterm set the titlebar to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PS1="\[\e]0;\u@\h: \w\a\]$PS1"
    ;;
*)
    ;;
esac

#4


1  

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:

我正在做这样的事情,在标题中显示我的pwd,它可以被修改成你想做的任何事情,标题:

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.

我只是把这个放到~/.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:

我用我最初的答案遇到了奇怪的虫子。最后我拆开了默认的Ubuntu PS1,把它分成了几个部分,结果发现其中一个部分是标题:

# 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\]"

#5


1  

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:

OP要求使用bash,但是其他人可能有兴趣了解(如上所述)使用zsh shell确实容易得多。例子:

# 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)

在preexec中,$1包含命令类型(需要启用shell历史,这似乎是一个合理的假设),$2扩展命令(shell别名等)和$3“非常扩展”命令(shell函数体)。(更多)

#6


0  

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.

您可以设置bash,使它在每次启动外部程序时向终端发送某个转义序列。如果您使用终端使用的转义序列来更新它们的标题,您的问题应该得到解决。

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.

我以前用过,所以我知道这是可能的。但我一时想不起来,也没有时间去研究细节。

#7


0  

Based on the the need to auto position putty windows I have modified my /etc/bash.bashrc file on a Debian/Ubuntu system. I have posted the full contents for completeness but the relevant bit to starts on the # Display command ... comment line.

由于需要自动定位腻子窗口,我修改了我的/etc/bash在Debian/Ubuntu系统上的bashrc文件。我已经发布了完整的内容,但是相关的位要从# Display命令开始……注释行。

# System-wide .bashrc file for interactive bash(1) shells.

# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
    debian_chroot=$(cat /etc/debian_chroot)
fi

# set a fancy prompt (non-color, overwrite the one in /etc/profile)
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '

# Display command run in title which allows us to distinguish Kitty/Putty
# windows and re-position easily using AutoSizer window utility. Based on a
# post here: http://mg.pov.lt/blog/bash-prompt.html
case "$TERM" in
xterm*|rxvt*)
    # Show the currently running command in the terminal title:
    # http://www.davidpashley.com/articles/xterm-titles-with-bash.html
    show_command_in_title_bar()
    {
        case "$BASH_COMMAND" in
            *\033]0*)
                # The command is trying to set the title bar as well;
                # this is most likely the execution of $PROMPT_COMMAND.
                # In any case nested escapes confuse the terminal, so don't
                # output them.
                ;;
            *)
                echo -ne "\033]0;${USER}@${HOSTNAME}: ${BASH_COMMAND}\007"
                ;;
        esac
    }
    trap show_command_in_title_bar DEBUG
    ;;
*)
    ;;
esac

# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
#    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#    ;;
#*)
#    ;;
#esac

# enable bash completion in interactive shells
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

# if the command-not-found package is installed, use it
if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
        function command_not_found_handle {
                # check because c-n-f could've been removed in the meantime
                if [ -x /usr/lib/command-not-found ]; then
                   /usr/bin/python /usr/lib/command-not-found -- "$1"
                   return $?
                elif [ -x /usr/share/command-not-found/command-not-found ]; then
                   /usr/bin/python /usr/share/command-not-found/command-not-found -- "$1"
                   return $?
                else
                   printf "%s: command not found\n" "$1" >&2
                   return 127
                fi
        }
fi

#8


0  

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.

请注意,如果使用$BASH_COMMAND,它不识别bash别名,并使用PROMPT_COMMAND显示完成命令,但是使用trap show running命令。