Answers:
您可以通过在显示提示之前显示第一行来轻松完成所需的操作。例如,以下内容\w
在第一行的左侧显示提示,在第一行\u@\h
的右侧显示提示。它利用$COLUMNS
包含终端宽度的变量和$PROMPT_COMMAND
在bash显示提示之前评估的参数。
print_pre_prompt ()
{
PS1L=$PWD
if [[ $PS1L/ = "$HOME"/* ]]; then PS1L=\~${PS1L#$HOME}; fi
PS1R=$USER@$HOSTNAME
printf "%s%$(($COLUMNS-${#PS1L}))s" "$PS1L" "$PS1R"
}
PROMPT_COMMAND=print_pre_prompt
.inputrc
了set show-mode-in-prompt on
。这两个不计算非prinable的长度ANSI CSI码,不正确包围他们\[
,并\]
通过@Mu心提到。请参阅此答案以获取解决方案。
根据我在这里找到的信息,我能够找到一种更简单的解决方案,以右对齐,同时在左右容纳可变长度的内容,包括对颜色的支持。为方便起见在此处添加...
关于颜色的注意事项:使用\033
转义符而不使用\[\]
分组来替代其他选项,证明是最兼容的,因此建议使用。
诀窍是先写右手边,然后使用回车(\r
)返回行首,并继续覆盖左手边的内容,如下所示:
prompt() {
PS1=$(printf "%*s\r%s\n\$ " "$(tput cols)" 'right' 'left')
}
PROMPT_COMMAND=prompt
我tput cols
在Mac OS X上使用来检索终端/控制台的宽度,terminfo
因为我的$COLUMNS
var没有被填充,env
但是您可以通过提供“ ”或您喜欢的任何其他值来代替可替换的“ *
”值。%*s
${COLUMNS}
下一个$RANDOM
用于生成不同长度内容的示例包括颜色,并显示了如何提取函数以将实现重构为可重用函数。
function prompt_right() {
echo -e "\033[0;36m$(echo ${RANDOM})\033[0m"
}
function prompt_left() {
echo -e "\033[0;35m${RANDOM}\033[0m"
}
function prompt() {
compensate=11
PS1=$(printf "%*s\r%s\n\$ " "$(($(tput cols)+${compensate}))" "$(prompt_right)" "$(prompt_left)")
}
PROMPT_COMMAND=prompt
由于printf
假定字符串的长度为字符数,因此我们需要补偿呈现颜色所需的字符数,因此,由于未打印的ANSI字符未进行补偿,因此您总是会发现它距离屏幕结尾较近。颜色所需的字符保持不变,并且您会发现printf也考虑了长度的变化,$RANDOM
例如由' 返回,这使我们的正确对齐保持不变。
这不是特殊的bash提示符转义序列的情况下(即\u
,\w
,\h
,\t
)不过,因为这些只会记录2的长度,因为bash将只显示提示时,翻译它们的printf已经呈现后弦。这不会影响左侧,但最好避免右侧。
但是,如果生成的内容将保持恒定的长度,则没有关系。与time \t
选项一样,它将始终在24时间内渲染相同数量的字符(8)。在这种情况下,我们只需要考虑补偿所需要的补偿,以适应计算出的2个字符之间的差异(打印时得出8个字符)。
请记住,您可能需要对\\\
某些转义序列进行三倍转义,否则这些转义序列将保留字符串的含义。与下面的示例一样,当前的工作目录转义符\w
没有其他意义,因此它可以按预期工作,但是time \t
,即表示制表符,如果不先三进制转义,则不能按预期工作。
function prompt_right() {
echo -e "\033[0;36m\\\t\033[0m"
}
function prompt_left() {
echo -e "\033[0;35m\w\033[0m"
}
function prompt() {
compensate=5
PS1=$(printf "%*s\r%s\n\$ " "$(($(tput cols)+${compensate}))" "$(prompt_right)" "$(prompt_left)")
}
PROMPT_COMMAND=prompt
欢乐!
以下内容会将当前日期和时间以红色显示在终端的RHS上。
# Create a string like: "[ Apr 25 16:06 ]" with time in RED.
printf -v PS1RHS "\e[0m[ \e[0;1;31m%(%b %d %H:%M)T \e[0m]" -1 # -1 is current time
# Strip ANSI commands before counting length
# From: https://www.commandlinefu.com/commands/view/12043/remove-color-special-escape-ansi-codes-from-text-with-sed
PS1RHS_stripped=$(sed "s,\x1B\[[0-9;]*[a-zA-Z],,g" <<<"$PS1RHS")
# Reference: https://en.wikipedia.org/wiki/ANSI_escape_code
local Save='\e[s' # Save cursor position
local Rest='\e[u' # Restore cursor to save point
# Save cursor position, jump to right hand edge, then go left N columns where
# N is the length of the printable RHS string. Print the RHS string, then
# return to the saved position and print the LHS prompt.
# Note: "\[" and "\]" are used so that bash can calculate the number of
# printed characters so that the prompt doesn't do strange things when
# editing the entered text.
PS1="\[${Save}\e[${COLUMNS:-$(tput cols)}C\e[${#PS1RHS_stripped}D${PS1RHS}${Rest}\]${PS1}"
好处:
shellcheck
清洁。.inputrc
有,则可以正常工作set show-mode-in-prompt on
。\[
,\]
以使在提示符下输入的编辑文本不会导致提示符奇怪地重新打印。注意:在执行$PS1
此代码之前,您需要确保正确封装了颜色序列\[
,\]
并且没有嵌套。
bash: local: can only be used in a function
,这很容易解决,并且之后,由于COLUMNS
未定义,它不会显示任何内容:必须替换为$(tput cols)
。如果将代码段保存在其他文件中,然后将其来源到中,则结果相同.bashrc
。
tput cols
如果$COLUMNS
未设置,我已经更新了要运行的代码。是的,此代码应在函数内部。我使用PROMPT_COMMAND='_prompt_bash_set'
并命名该函数_prompt_bash_set
。
我只是以为我会把我扔在这里。它与GRML zsh提示符几乎完全相同(除了zsh更新,它的提示符在新行和退格处要好一点-不可能在bash中复制...至少在目前是非常困难的)。
我花了三天时间(仅在运行arch的笔记本电脑上进行了测试),所以这是屏幕截图,然后是〜/ .bashrc中的内容:)
警告 -这有点疯狂
除了重要的一点 -每个^[
(诸如^[[34m
)都是逃脱字符(char)27
。我知道如何插入的唯一方法是输入ctrl+([v)(即同时按下[并按住不放)。vctrl
# grml battery?
GRML_DISPLAY_BATTERY=1
# battery dir
if [ -d /sys/class/power_supply/BAT0 ]; then
_PS1_bat_dir='BAT0';
else
_PS1_bat_dir='BAT1';
fi
# ps1 return and battery
_PS1_ret(){
# should be at beg of line (otherwise more complex stuff needed)
RET=$?;
# battery
if [[ "$GRML_DISPLAY_BATTERY" == "1" ]]; then
if [ -d /sys/class/power_supply/$_PS1_bat_dir ]; then
# linux
STATUS="$( cat /sys/class/power_supply/$_PS1_bat_dir/status )";
if [ "$STATUS" = "Discharging" ]; then
bat=$( printf ' v%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
elif [ "$STATUS" = "Charging" ]; then
bat=$( printf ' ^%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
elif [ "$STATUS" = "Full" ] || [ "$STATUS" = "Unknown" ] && [ "$(cat /sys/class/power_supply/$_PS1_bat_dir/capacity)" -gt "98" ]; then
bat=$( printf ' =%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
else
bat=$( printf ' ?%d%%' "$( cat /sys/class/power_supply/$_PS1_bat_dir/capacity )" );
fi;
fi
fi
if [[ "$RET" -ne "0" ]]; then
printf '\001%*s%s\r%s\002%s ' "$(tput cols)" ":( $bat " "^[[0;31;1m" "$RET"
else
printf '\001%*s%s\r\002' "$(tput cols)" "$bat "
fi;
}
_HAS_GIT=$( type 'git' &> /dev/null );
# ps1 git branch
_PS1_git(){
if ! $_HAS_GIT; then
return 1;
fi;
if [ ! "$( git rev-parse --is-inside-git-dir 2> /dev/null )" ]; then
return 2;
fi
branch="$( git symbolic-ref --short -q HEAD 2> /dev/null )"
if [ "$branch" ]; then
printf ' \001%s\002(\001%s\002git\001%s\002)\001%s\002-\001%s\002[\001%s\002%s\001%s\002]\001%s\002' "^[[0;35m" "^[[39m" "^[[35m" "^[[39m" "^[[35m" "^[[32m" "${branch}" "^[[35m" "^[[39m"
fi;
}
# grml PS1 string
PS1="\n\[\e[F\e[0m\]\$(_PS1_ret)\[\e[34;1m\]${debian_chroot:+($debian_chroot)}\u\[\e[0m\]@\h \[\e[01m\]\w\$(_PS1_git) \[\e[0m\]% "
我仍在努力使颜色可配置,但我对现在的颜色感到满意。
目前正致力于解决疯狂^[
角色和轻松进行颜色切换的问题:)
您可以printf
用来进行右对齐:
$ printf "%10s\n" "hello"
hello
$ PS1='$(printf "%10s" "$somevar")\w\$ '
加上Giles的答案,我写了一些东西来更好地处理颜色(前提是颜色正确地封装在\[
和中\]
。这是逐个案的,并且不能处理所有情况,但是它使我可以将PS1L设置为与PS1相同的语法并将(无色)日期用作PS1R。
function title {
case "$TERM" in
xterm*|rxvt*)
echo -en "\033]2;$1\007"
;;
*)
;;
esac
}
print_pre_prompt() {
PS1R=$(date)
PS1L_exp="${PS1L//\\u/$USER}"
PS1L_exp="${PS1L_exp//\\h/$HOSTNAME}"
SHORT_PWD=${PWD/$HOME/~}
PS1L_exp="${PS1L_exp//\\w/$SHORT_PWD}"
PS1L_clean="$(sed -r 's:\\\[([^\\]|\\[^]])*\\\]::g' <<<$PS1L_exp)"
PS1L_exp=${PS1L_exp//\\\[/}
PS1L_exp=${PS1L_exp//\\\]/}
PS1L_exp=$(eval echo '"'$PS1L_exp'"')
PS1L_clean=$(eval echo -e $PS1L_clean)
title $PS1L_clean
printf "%b%$(($COLUMNS-${#PS1L_clean}))b\n" "$PS1L_exp" "$PS1R"
}
它在github上:dbarnett / dotfiles / right_prompt.sh。我在.bashrc中像这样使用它:
source $HOME/dotfiles/right_prompt.sh
PS1L='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]'
PS1='\[\033[01;34m\]\w\[\033[00m\]\$ '
PROMPT_COMMAND=print_pre_prompt
注意:我还在PS1R之后添加了换行符,这没有视觉上的区别,但是,如果您在命令历史记录中回滚某些命令,似乎可以防止提示变得乱码。
我确信其他人可以对此进行改进,并且可以概括一些特殊情况。
这是基于PROMPT_COMMAND
和的解决方案tput
:
function __prompt_command() {
local EXIT="$?" # This needs to be first
history -a
local COL=$(expr `tput cols` - 8)
PS1="💻 \[$(tput setaf 196)\][\[$(tput setaf 21)\]\W\[$(tput setaf 196)\]]\[$(tput setaf 190)\]"
local DATE=$(date "+%H:%M:%S")
if [ $EXIT != 0 ]; then
PS1+="\[$(tput setaf 196)\]\$" # Add red if exit code non 0
tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 196)$DATE"; tput rc
else
PS1+="\[$(tput setaf 118)\]\$"
tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 118)$DATE"; tput rc
fi
PS1+="\[$(tput setaf 255)\] "
}
PROMPT_COMMAND="__prompt_command"
魔术是由以下人员执行的:
tput sc;tput cuu1; tput cuf $COL;echo "$(tput setaf 196)$DATE"; tput rc
细分如下:
tput sc # saved the cursor position
tput cuu1 # up one line
tput cuf $COL # move $COL characters left
echo "$(tput setaf 196)$DATE" # set the colour and print the date
tput rc # restore the cursor position
在PS1中,tput
以\ [\]进行转义,因此不计入显示的长度。