【问题标题】:Bash - Update terminal title by running a second commandBash - 通过运行第二个命令更新终端标题
【发布时间】:2011-07-01 20:37:36
【问题描述】:

在我的 Ubuntu 终端上,我经常运行长时间运行的程序。而且由于这些程序很多,我总是忘记哪个终端是哪个程序的,除非我通过所有这些选项卡。因此,每当我运行命令时,我想找到一种将终端标题更新为程序名称的方法。我不想手动做。

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

【问题讨论】:

    标签: linux bash shell terminal


    【解决方案1】:

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

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

    【讨论】:

    • 哪个环境变量会包含当前的“命令”?
    【解决方案2】:

    我有一些答案给你 :) 你是对的,你使用 gnome-terminal 并不重要,但你使用什么命令 shell 很重要。这在zsh 中要容易得多,但在接下来的内容中,我将假设您使用的是bash,并且它是一个相当新的版本(> 3.1)。

    首先:

    哪个环境变量会 包含当前的“命令”?

    有一个环境变量或多或少有你想要的 - $BASH_COMMAND。只有一个小问题,那就是它只会显示管道中的最后一个命令。我也不是 100% 确定它会如何处理子外壳的组合:)

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

    我一直在考虑这个问题,现在我明白了你想要做什么,我意识到真正的问题是你需要在每个命令之前更新标题之前。这意味着$PROMPT_COMMAND$PS1 环境变量作为可能的解决方案已被淘汰,因为它们仅在命令返回之后执行。

    bash 中,我能想到的实现您想要的唯一方法是(ab)使用调试信号。所以这里有一个解决方案——把它贴在.bashrc 的末尾:

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

    为了解决管道问题,我一直在搞砸:

    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
    

    但我不保证它是完美的!

    【讨论】:

    • 非常感谢。这是 Dennis 的另一个问题的链接,它处理了我的确切问题。 davidpashley.com/articles/xterm-titles-with-bash.html。为什么有些文档必须挖得这么深;)?
    • 你答案的最后一部分正确吗?我得到:-bash: PROMPT_COMMAND: line 0: syntax error near unexpected token ';'-bash: PROMPT_COMMAND: line 0: ';export PREV_COMMAND=""' 当把它放在我的~/.bashrc底部时
    • @Suan -- 我相信是的,这正是我正在使用的,并且有效。 John 下面的答案提供了另一种(可能更好)方法来解决我的答案的最后一部分试图解决的问题,所以如果这对你很重要,我会选择他的解决方案:)
    • 对我来说,这个优于 PROMPT_COMMAND 解决方案,因为陷阱发生在命令运行之前,因此会立即更新标题。因此,例如,如果我 ssh 进入另一个 shell,标题将立即反映这一点,而不是在我退出该 shell 后等待更新提示。所以我最终得到了function settitle { LASTCMD=$(history 1 | sed "s/^[ ]*[0-9]*[ ]*//g"); echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD} ${LASTCMD}\007"; } trap 'settitle' DEBUG 注意:由于 cmets 不喜欢多行,我添加了分号,但我实际上并没有使用 1 行格式
    • 所以,这对我有用,但仅在一定程度上:命令运行时标题会更新,然后在命令完成后恢复为标准标题。有没有办法让它坚持到下一个命令? PS - 可能不相关,但我不得不把它放在 .bash_profile 因为我无法让 Git Bash 运行 .bashrc...
    【解决方案3】:

    试试这个:

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

    感谢history 1,它甚至可以处理复杂的表达式,例如:

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

    对于哪些依赖于 $BASH_COMMAND 或 $@ 的方法失败。例如simon 的显示:

    true | echo $? | cat
    

    感谢 Gilles 和 simon 提供灵感。

    【讨论】:

    • 好,history 1 比不尊重别名命令的 $BASH_COMMAND 好,它显示 ls -hF --show-control-chars --color=auto
    • nice :) 但为什么是\033]2; 而不是\033]0;?好的,我自己通过askubuntu.com/a/832382/929 找到它导致invisible-island.net/xterm/ctlseqs/… 2 表示仅更改 window 标题,而 0 还包括 icon 名称。显然人们甚至可以在那里改变一些颜色......
    • 是否可以将它放在 bashrc 中,而不会让它陷入第一个并在终端启动后立即退出标题?
    • 我想知道他的第一个命令是否可以安全添加,尤其是“调试”的东西
    • 到@qrtLs 的观点:DEBUG 陷阱将破坏$_。见echo $(echo hi) && echo $_。一种解决方法是保存它并使用 noop 重新实例化:trap '__prevarg="$_"; echo -ne "\033]2;$_hostinfo:$PWD $(history 1 | sed "s/^ *[0-9]* *//g")\007"; : "$__prevarg"' DEBUG
    【解决方案4】:

    我正在做这样的事情,在标题中显示我的pwd,可以对其进行修改以对标题做任何你想做的事情:

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

    我刚刚把它扔进了我的~/.bash_aliases

    更新

    我的原始答案遇到了奇怪的错误。我最终把默认的 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}"
    

    不分解变量,它看起来像这样:

    PS1="\[\033[1;33m\]\[\e]0;\u@\h:\w\a\]${debian_chroot:+($debian_chroot)}\w\n$ \[\033[0m\]"
    

    【讨论】:

      【解决方案5】:

      我知道 stoutie 想要做什么,但它比需要的工作多得多。并且不会导致由于重新定义“cd”并进行所有测试只是为了更改目录而可能发生的各种其他潜在的坏事。 Bash 已内置支持其中的大部分内容。

      您可以在设置当前 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
      

      【讨论】:

      • 我的原始答案最终遇到了奇怪的错误。所以我最终选择了 Ubuntu 中的默认 PS1,并发现其中一个部分就是标题。见我上面的回答。
      • 玩得好!您的更新更像是我个人的实际编写方式(颜色和部件的变量)我不使用默认的 ubuntu,因为我对其进行了大量自定义(我正在使用 git 分支,脏状态,还有很多其他愚蠢的事情,后台工作的数量......)我只是想展示有人可以如何使用任何 PS1 并为它添加标题
      【解决方案6】:

      基于auto position putty windows 的需要,我在Debian/Ubuntu 系统上修改了我的/etc/bash.bashrc 文件。为了完整起见,我已经发布了完整的内容,但相关位从 # Display command ... 评论行开始。

      # 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
      

      【讨论】:

        【解决方案7】:

        OP 要求bash,但其他人可能有兴趣了解 (as mentioned above) 使用 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" }
        

        preexec 中,$1 包含键入的命令(需要启用 shell 历史记录,这似乎是一个公平的假设),$2 扩展命令(shell 别名等)和 $3 “非常扩展”的命令(shell 函数体)。 (more)

        【讨论】:

          【解决方案8】:

          我已经测试了三种方法,都可以,你可以使用任何一种。

          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
          

          请注意如果使用 $BASH_COMMAND,它不识别 bash 别名,并使用 PROMPT_COMMAND 显示完成命令,但使用陷阱显示运行命令。

          【讨论】:

            【解决方案9】:

            由于这两个错误(724110740188),从 gnome-terminal 3.14 中删除了一些旧方法。

            在 Ubuntu 20.04 中

            PS1=$PS1"\[\e]0;New_Terminal_Name\a\]"
            

            \[ 开始一系列非打印字符

            \e]0; 是设置终端标题的字符序列。 Bash 识别此序列并使用以下字符设置图块。数字 0 原来是引用 title 属性的值。

            New_Terminal_Name 是我们给的图块

            \a 是 ASCII 响铃字符,在这种情况下,它也标志着要从 Bash 读取的 tile 的结尾。

            \] 结束一系列非打印字符

            我们可以创建一个函数以供将来使用

            function set_title(){
             if [ -z "$PS1_BACK" ];  # set backup if it is empty
             then
              PS1_BACK="$PS1"
             fi
            
             TITLE="\[\e]0;$*\a\]"
             PS1="${PS1_BACK}${TITLE}"
            }
            

            使用文本编辑器打开主目录中的 ~/.bashrc 文件,并在其末尾附加上述函数。保存并关闭。

            要立即使用它,请将其源到当前终端。

            source ~/.bashrc
            

            我们可以这样使用它

            set_title <New terminal tab title>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-06-23
              • 1970-01-01
              • 2020-09-07
              • 2017-01-25
              • 2018-01-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多