【问题标题】:Creating a Bash command prompt with a red $ after failure of previous command在上一个命令失败后创建带有红色 $ 的 Bash 命令提示符
【发布时间】:2011-08-21 01:39:50
【问题描述】:

我是 Bash 编程新手,我正在努力创建一个自定义 Bash 命令提示符。我的目标是创建一个提示,仅在登录名和主机名与我通常使用的不同时才显示它们。我还希望在受 Git 版本控制的目录中将当前 Git 分支附加到命令提示符。

我想将登录名和主机名部分涂成绿色,将目录路径涂成蓝色,将 Git 分支部分涂成粉红色,并将分隔符(: 和 $ 字符)涂成白色。但是,当之前执行的命令返回的不是零时,我想将 $ 分隔符涂成红色。没有颜色的一般格式如下所示:

loginname@hostname:~/current/path:branchname$

唯一必须的部分是目录路径和 $ 字符。这是我为 .bashrc 文件编写的代码:

MYNAME="gwen"
MYHOST="gwen-laptop"

RED="\[\033[31m\]"
WHITE="\[\033[0m\]"
GREEN="\[\033[01;32m\]"
BLUE="\[\033[01;34m\]"
PINK="\[\033[01;35m\]"

DOLLAR="if [ \$? = 0 ]; then echo ${WHITE}\$; else echo ${RED}\$${NORMAL}; fi"
GITBRN='$(__git_ps1 "\033[0m:\033[01;35m%s")'

USERNM="if [ \u != ${MYNAME} ]; then whoami; fi;"
HOSTNM="if [ \h != ${MYHOST} ]; then echo -n @; hostname; fi;"
COLONM="if [ \u != ${MYNAME} ] || [ \h != ${MYHOST} ]; then echo -n :; fi;"

PS1="${GREEN}\`${USERNM}\`\`${HOSTNM}\`${WHITE}\`${COLONM}\`${BLUE}\w${GITBRN}\`${DOLLAR}\` "

此代码符合我的所有要求,除了 $ 字符始终保持白色,并且在适当的时候不将其涂成红色。 (我怀疑问题是DOLLAR中的“\$?”引用了之前执行的命令,但是DOLLAR在构建PS1时最后执行,所以之前的执行语句不再是PS1构建开始之前运行的命令;它是什么这是为了创建命令提示符而执行的。)我不确定如何解决这个问题

这段代码很丑,需要重构。我试图将所有颜色代码移动到它们自己的变量中,但是当我在 GITBRN 的代码中使用这些颜色变量时,事情变得混乱,所以我最终在那里使用了文字颜色。

我花了一整天的时间试图让这段代码正常工作,但我想我现在无处可去。任何关于如何在适当的时候将美元符号染成红色的建议将不胜感激。我也愿意接受有关重构代码以使其更清晰、更易读的建议。

附:我是 Ubuntu Linux (Lucid Lynx) 用户。

【问题讨论】:

  • 与您手头的问题无关:我相信这样做就足够了 if (hostnamecondition); then HOSTNM=''; else HOSTNM="@$(hostname)";fi 或类似的东西。我认为主机名通常不会改变:当你 ssh 到另一台机器时,你会在那里产生一个新的 bash,它会再次运行你的代码。每次显示提示时不检查主机名会稍微提高性能。
  • 这里的问题是你的提示定义中包含执行的命令,运行后会设置$?。您只需将其复制到自定义变量中,尽管我无法完全解决范围问题,因此下面的答案仍然是目前最好的解决方案。

标签: bash shell refactoring return-value command-prompt


【解决方案1】:

使用PROMPT_COMMAND 变量,根据 bash 手册页,该变量在每个主要提示之前执行。

例如(这还不行,我正在努力让它正常工作,但我认为这是可能的):

PROMPT_COMMAND="if [ \$? = 0 ]; then DOLLAR="${WHITE}\$${NORMAL}"; else DOLLAR="${RED}\$${NORMAL}"; fi"

编辑:由于执行命令和PS1 中的非打印字符感到沮丧(\[\] 有时会按字面意思打印出来,而不是用作PS1 的提示),我想出了这个(将... 替换为提示符中的任何内容):

PROMPT_COMMAND='if [ $? = 0 ]; then DOLLAR_COLOR="\033[0m"; else DOLLAR_COLOR="\033[31m"; fi'
PS1='...\[$(echo -ne $DOLLAR_COLOR)\]$\[\033[m\] '

当然,使用$() 你可以把你喜欢的任何部分放在PS1 中,而不是使用PROMPT_COMMAND,我只是喜欢这样,PROMPT_COMMAND 包含逻辑,PS1 包含显示命令。

【讨论】:

  • 这是个好主意!我不知道这个 PROMPT_COMMAND 的存在。谢谢!
  • @Gwen Avery 这是个好主意,我正在考虑自己使用它:)
【解决方案2】:

我让它工作了:

PROMPT_COMMAND='if [ $? = 0 ]; then PS1="\[\e[32;1m\]\u@\[\e[0m\e[30;47m\]\H\[\e[0m\]:\[\e[34;1m\]\w\[\e[0m\]$ "; else PS1="\[\e[31;1m\]\u@\[\e[0m\e[31;47m\]\H\[\e[0m\]:\[\e[31;1m\]\w\[\e[0m\]$ "; fi'

站在@jtbandes 的立场上。 @jtbandes 是这个想法的原作者。

【讨论】:

  • 你认为有可能在命令失败时显示红色,而不是在空命令行上按回车键时显示红色吗?
【解决方案3】:

这里是 Alexsandr's answer 修改为仅在命令失败时显示红色,而不是在您按 Stéphane 要求的空命令行上按 enter 时显示红色。

trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG
read -r -d '' PROMPT_COMMAND << 'END'
    if [ $? = 0 -o $? == 130 -o "$PREVIOUS_COMMAND" = ": noop" ]; then
        PS1='\[\e[32;1m\]\u@\[\e[0m\e[30;47m\]\H\[\e[0m\]:\[\e[34;1m\]\w\[\e[0m\]$ '
    else
        PS1='\[\e[31;1m\]\u@\[\e[0m\e[31;47m\]\H\[\e[0m\]:\[\e[31;1m\]\w\[\e[0m\]$ '
    fi
    : noop
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-30
    • 2015-11-14
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-02
    • 2019-10-24
    相关资源
    最近更新 更多