我一直在尝试自定义我的 Bash 提示符,使其看起来像这样
[feralin@localhost ~]$ _
有颜色。我设法获得恒定的颜色(每次看到提示时的颜色相同),但如果最后一个命令具有非零退出状态,我希望用户名(“feralin”)显示为红色,而不是绿色。我想出了:
\e[1;33m[$(if [[ $? == 0 ]]; then echo "\e[0;31m"; else echo "\e[0;32m"; fi)\u\e[m@\e[1;34m\h \e[0;35m\W\e[1;33m]$ \e[m
但是,根据我的观察,当
$(if ...; fi)
运行时,.bashrc
似乎被评估一次,并且结果将永远被替换。这使得名称始终为绿色,即使最后一个退出代码非零(如 echo $?
)。这是正在发生的事情吗?或者只是我的提示有其他问题?长问短,如何获得使用最后退出代码的提示?
当您开始接近复杂的 PS1 时,您可能会考虑使用
PROMPT_COMMAND
。这样,您将其设置为一个函数,它将在每个命令之后运行以生成提示。
您可以在您的
~/.bashrc
文件中尝试以下操作:
PROMPT_COMMAND=__prompt_command # Function to generate PS1 after CMDs
__prompt_command() {
local EXIT="$?" # This needs to be first
PS1=""
local RCol='\[\e[0m\]'
local Red='\[\e[0;31m\]'
local Gre='\[\e[0;32m\]'
local BYel='\[\e[1;33m\]'
local BBlu='\[\e[1;34m\]'
local Pur='\[\e[0;35m\]'
if [ $EXIT != 0 ]; then
PS1+="${Red}\u${RCol}" # Add red if exit code non 0
else
PS1+="${Gre}\u${RCol}"
fi
PS1+="${RCol}@${BBlu}\h ${Pur}\W${BYel}$ ${RCol}"
}
这应该可以实现您想要的效果。如果您想查看我使用 __prompt_command
函数执行的所有操作,请查看我的 bashrc 的
子文件。
如果您不想使用提示命令,则需要考虑两件事:
$?
的值。否则它将被覆盖。$
(因此在分配它时不会对其进行评估)使用变量的工作示例
PS1="\$(VALU="\$?" ; echo \$VALU ; date ; if [ \$VALU == 0 ]; then echo zero; else echo nonzero; fi) "
没有变量的工作示例
这里 if 需要是第一件事,在任何覆盖
$?
的命令之前。
PS1="\$(if [ \$? == 0 ]; then echo zero; else echo nonzero; fi) "
注意
\$()
是如何转义的,因此它不会立即执行,而是在每次使用 PS1 时执行。还有\$?
的所有用途。
紧凑型解决方案:
PS1='... $(code=${?##0};echo ${code:+[error: ${code}]})'
此方法不需要
PROMPT_COMMAND
(显然这有时会更慢),并且如果退出代码非零则打印 [error: <code>]
,如果为零则不打印任何内容:
... > false
... [error: 1]> true
... >
根据您的喜好更改
[error: ${code}]
部分,其中 ${code}
是要打印的非零代码。
请注意使用
'
来确保内联 $()
shell 在稍后评估 PS1 时执行,而不是在 shell 启动时执行。
作为奖励,您可以通过在前面添加
\e[01;31m
并在重置后添加 \e[00m
使其呈现红色:
PS1='... \e[01;31m$(code=${?##0};echo ${code:+[error: ${code}]})\e[00m'
--
工作原理:
${?##0}
将读取上一个命令的退出代码$?
##
将从头开始删除任何0
模式,有效地使0
结果成为空变量(感谢@blaskovicz的技巧)code
变量,因为我们需要进行另一次替换,并且它们不能嵌套${code:+REPLACEMENT}
(非空)时,REPLACEMENT
才会打印code
部分[error: ${code}]
我想保留默认的 Debian 颜色,打印确切的代码,并且仅在失败时打印它:
# Show exit status on failure.
PROMPT_COMMAND=__prompt_command
__prompt_command() {
local curr_exit="$?"
local BRed='\[\e[0;91m\]'
local RCol='\[\e[0m\]'
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
if [ "$curr_exit" != 0 ]; then
PS1="[${BRed}$curr_exit${RCol}]$PS1"
fi
}
当退出代码为零时,以下内容提供了一个前导的绿色复选标记,在所有其他情况下提供了一个红色十字。其余部分是标准的彩色提示。可以修改
printf
语句以呈现最初请求的两种状态。
PS1='$(if [ $? -eq 0 ]; then printf "\033[01;32m""\xE2\x9C\x93"; else printf "\033[01;31m""\xE2\x9C\x95"; fi) \[\e[00;32m\]\u@\h\[\e[00;30m\]:\[\e[01;33m\]\w\[\e[01;37m\]\$ '
为什么我自己没有想到这一点?我发现这非常有趣,并将此功能添加到我的“info-bar”项目中。如果最后一个命令失败,眼睛会变红。
#!/bin/bash
eyes=(O o ∘ ◦ ⍤ ⍥) en=${#eyes[@]} mouth='_'
face () { # gen random face
[[ $error -gt 0 ]] && ecolor=$RED || ecolor=$YLW
if [[ $1 ]]; then printf "${eyes[$[RANDOM%en]]}$mouth${eyes[$[RANDOM%en]]}"
else printf "$ecolor${eyes[$[RANDOM%en]]}$YLW$mouth$ecolor${eyes[$[RANDOM%en]]}$DEF"
fi
}
info () { error=$?
[[ -d .git ]] && { # If in git project folder add git status to info bar output
git_clr=('GIT' $(git -c color.ui=always status -sb)) # Colored output 4 info
git_tst=('GIT' $(git status -sb)) # Simple output 4 test
}
printf -v line "%${COLUMNS}s" # Set border length
date=$(printf "%(%a %d %b %T)T") # Date & time 4 test
test=" O_o $PWD ${git_tst[*]} $date o_O " # Test string
step=$[$COLUMNS-${#test}]; [[ $step -lt 0 ]] && step=0 # Count spaces
line="$GRN${line// /-}$DEF\n" # Create lines
home="$BLD$BLU$PWD$DEF" # Home dir info
date="$DIM$date$DEF" # Colored date & time
#------+-----+-------+--------+-------------+-----+-------+--------+
# Line | O_o |homedir| Spaces | Git status | Date| o_O | Line |
#------+-----+-------+--------+-------------+-----+-------+--------+
printf "$line $(face) $home %${step}s ${git_clr[*]} $date $(face) \n$line" # Final info string
}
PS1='${debian_chroot:+($debian_chroot)}\n$(info)\n$ '
case "$TERM" in xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)} $(face 1) \w\a\]$PS1";;
esac
改进端庄的回答:
我认为这很重要,因为退出状态并不总是0或1。
if [ $EXIT != 0 ]; then
PS1+="${Red}${EXIT}:\u${RCol}" # Add red if exit code != 0
else
PS1+="${Gre}${EXIT}:\u${RCol}" # Also displays exit status
fi
要保留原始提示格式(不仅仅是颜色), 您可以将以下内容附加到文件末尾
~/.bashrc
:
PS1_ORIG=$PS1 # original primary prompt value
PROMPT_COMMAND=__update_prompt # Function to be re-evaluated after each command is executed
__update_prompt() {
local PREVIOUS_EXIT_CODE="$?"
if [ $PREVIOUS_EXIT_CODE != 0 ]; then
local RedCol='\[\e[0;31m\]'
local ResetCol='\[\e[0m\]'
local replacement="${RedCol}\u${ResetCol}"
# Replace username color
PS1=${PS1_ORIG//]\\u/]$replacement}
## Alternative: keep same colors, append exit code
#PS1="$PS1_ORIG[${RedCol}error=$PREVIOUS_EXIT_CODE${ResetCol}]$ "
else
PS1=$PS1_ORIG
fi
}
另请参阅有关保留用户名颜色并仅在原始提示格式末尾附加红色错误代码的替代方法的评论。
function my_prompt {
local retval=$?
local field1='\u@\h'
local field2='\w'
local field3='$([ $SHLVL -gt 1 ] && echo \ shlvl:$SHLVL)$([ \j -gt 0 ] && echo \ jobs:\j)'"$([ ${retval} -ne 0 ] && echo \ exit:$retval)"
local field4='\$'
PS1=$'\n'"\e[0;35m${field1}\e[m \e[0;34m${field2}\e[m\e[0;31m${field3}\e[m"$'\n'"\[\e[0;36m\]${field4}\[\e[m\] "
}
PROMPT_COMMAND="my_prompt; ${PROMPT_COMMAND}"
PROMPT=$'\n''%F{magenta}%n@%m%f %F{blue}%~%f%F{red}%(2L. shlvl:%L.)%(1j. jobs:%j.)%(?.. exit:%?)%f'$'\n''%F{cyan}%(!.#.$)%f '
PS1="\${?#0} \$ "
退出状态 | PS1渲染 |
---|---|
0 |
|
x |
|
您可以显示最后一个命令的退出状态,而无需修改如上所示的
$?
。 PROMPT_COMMAND
和 subshell $(...)
方法都会修改最后一个退出状态参数 $?
。
$ man bash
BASH(1) ...
PARAMETERS ...
Special Parameters ...
? Expands to the exit status of the most recently executed foreground pipeline.
用 ANSI 颜色代码包裹这个内含物,它也可以脱颖而出。
declare -A _c
_c[red_ul]="\033[0;31;4m"
_c[nc]="\033[0m"
PS1="${_c[red_ul]}\${?##0}${_c[nc]} \$ "
注意:转义
\$
提示符,因此它在 root shell 中显示为 #
(“EUID = 0”)。
_ret(){ return ${1:-0};}
$ _ret
$ _ret 1
1 $
1 $ _ret 2
2 $ :
$