bash美化(bash配置)

前言

最近在折腾Duo S觉得上面bash一点颜色都没有,忒难看,于是开始自己动手美化bash,最终得到这篇文章的.bashrc文件,还请大家过目!
由于这不算一个项目,所以就不把老版本内容保留了。最新版代码就贴在博客,可以通过右侧导航栏快速移到那里!

效果展示-v2.8.2

效果展示截图 一份~ 请注意查收~

路径折叠仿照fish,父目录为单字符缩写(隐藏目录为两个字符)。耗时变为复合型,将整条命令的时间记录(即上条提示符命令被执行到这个提示符出现的时间,精确度为1ms)
image

代码展示-v2.8.2

重要消息

ble.sh 不建议搭配使用,建议搭配thefuck,因为ble.sh篡改$PROMPT_COMMAND,导致计时功能不稳定。已用+=()确保不被覆盖

#!/bin/bash
# ~/.bashrc
# Version     : 2.8.2
# Update-time : 2025-8-17
# Author      : BiaoZyx
# Email       : BiaoZyx@outlook.com

# 在交互shell启用bash自动补全,建议安装`bash-completion`并启用
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
############################## 自定义 ##############################
## 变量
# 如果使用opkg,添加以下内容
#export PATH=$PATH:/opt/bin

# ----- 备忘录 -----
memo=/home/xue/文档/memo.xue

## 别名
alias ls="ls --color -F"      # 自定义`ls`,可自行删减
alias lah="ls -lah"  # 自定义`ls`,可自行删减
alias ll="ls -lh"    # 自定义`ls`,可自行删减
alias ip='ip --color=auto'    # `ip a`的彩色,很有必要

if [[ -z $memo ]]; then
    alias memo="echo 备忘录路径为空!请手动添加到~/.bashrc!"
else
    alias memo="lolcat $memo"
fi

alias irssi-rizon="irssi -c irc.rizon.net"    # 我的`irssi`快捷配置

alias d--="c++ -x cpp"

# `thefuck`配置,安装才加载
if [[ -e /usr/bin/thefuck ]]; then
    eval $( thefuck --alias f )
fi
####################################################################

# fish风格路径折叠
function _fish_collapsed_pwd() {
    local pwd="$1"
    local home="$HOME"
    local size=${#home}
    [[ $# == 0 ]] && pwd="$PWD"
    [[ -z "$pwd" ]] && return

    if [[ "$pwd" == "/" ]]; then
        echo "/"
        return
    elif [[ "$pwd" == "$home" ]]; then
        echo "~"
        return
    fi

    # 替换 $HOME 为 ~
    [[ "$pwd" == "$home/"* ]] && pwd="~${pwd:$size}"

    # 分割路径
    local IFS="/"
    local elements=($pwd)
    local length=${#elements[@]}

    for ((i=0; i<length-1; i++)); do  # 不处理最后一个元素
        local elem="${elements[$i]}"
        if [[ -n "$elem" ]]; then
            if [[ "$elem" == .* ]]; then
                # 隐藏文件夹(以 . 开头)显示前 2 个字符
                elements[$i]="${elem:0:2}"
            else
                # 普通文件夹显示第 1 个字符
                elements[$i]="${elem:0:1}"
            fi
        fi
    done

    # 重新组合路径
    IFS="/"
    echo "${elements[*]}"
}

# 颜色定义
RESET='\[\033[0m\]'
USER_COLOR='\[\033[1;34m\]'
HOST_COLOR='\[\033[1;33m\]'
PATH_COLOR='\[\033[1;36m\]'
GIT_COLOR='\[\033[1;32m\]'
TIME_COLOR='\[\033[0;35m\]'
SUCCESS_COLOR='\[\033[1;32m\]'
ERROR_COLOR='\[\033[1;31m\]'
PROMPT_COLOR='\[\033[1;37m\]'

# Root用户颜色
[[ $(id -u) -eq 0 ]] && USER_COLOR='\[\033[1;31m\]'

# Git分支检测
get_git_branch() {
    git branch 2>/dev/null | sed -n '/^\*/s/^\* //p' | awk '{print "|"$1}'
}

############################## 精准耗时提示符 ##############################

# 智能时间格式化
format_duration() {
    local ns=$1
    local ms=$(( (ns + 500000) / 1000000 ))  # 四舍五入到毫秒

    # 强制最小显示50ms(解决终端渲染误差)
    #(( ms < 50 )) && ms=50

    if (( ms >= 1000 )); then
            local sec=$(( ms / 1000 ))
            local remainder=$(( ms % 1000 ))
            if (( sec >= 60 )); then
                local min=$(( sec / 60 ))
                local sec_remain=$(( sec % 60 ))
                if ((min >= 60)); then
                    local hour=$((min / 60))
                    local min_remain=$((min % 60))
                    printf "(${TIME_COLOR}%dh %02dm %02d.%03ds${RESET})" $hour $min_remain $sec_remain $remainder
                else
                    printf "(${TIME_COLOR}%dm %02d.%03ds${RESET})" $min $sec_remain $remainder
                fi
            else
                printf "(${TIME_COLOR}%d.%03ds${RESET})" $sec $remainder
            fi
        else
            printf "(${TIME_COLOR}%dms${RESET})" $ms
        fi
    }

# 命令计时控制
__command_start_time=""
__last_prompt_time=""

trap '[[ -z "$__command_start_time" ]] && __command_start_time=$(date +%s%N)' DEBUG

set_accurate_prompt() {
    local last_status=$?
    local current_time=$(date +%s%N)

    # 计算耗时
    local duration_display=""
    if [[ -n "$__command_start_time" ]]; then
        local duration_ns=$((current_time - __command_start_time))
        duration_display=$(format_duration "$duration_ns")
        __command_start_time=""
    elif [[ -n "$__last_prompt_time" ]]; then
        local idle_ns=$((current_time - __last_prompt_time))
        duration_display=$(format_duration "$idle_ns")
    fi

    # 状态指示
    local status_indicator="${SUCCESS_COLOR}^o^"
    (( last_status != 0 )) && status_indicator="${ERROR_COLOR}>_<:$last_status"

    # 构建提示符
    PS1="╭─[${USER_COLOR}\u${RESET}@${HOST_COLOR}\h${RESET}:${PATH_COLOR}$(_fish_collapsed_pwd)${RESET}${GIT_COLOR}$(get_git_branch)${RESET}]—{${status_indicator}${RESET}}—(\t)—${duration_display}"
    PS1+="\n╰─${PROMPT_COLOR}\\\$${PATH_COLOR}>${RESET} "

    __last_prompt_time=$current_time
}

PROMPT_COMMAND+=("set_accurate_prompt")

# 欢迎界面
if [[ -e /usr/bin/figlet ]]; then
    figlet_lock_file="/tmp/figlet_lock_$$"
    # 使用 $$ 作为文件名的一部分,确保每个进程都有自己的锁文件
    # 检查锁文件是否存在
    if [ ! -f "$figlet_lock_file" ]; then
        # 创建锁文件并执行 figlet
        touch "$figlet_lock_file"
        echo "         _   _ _
/\\_/\\   | | | (_)
(o.o)   | |_| | |_
> ^ < . |  _  | ( )
/   \\ . |_| |_|_|/
"
        figlet "$USER! "
    fi
fi
trap 'rm -f "$figlet_lock_file"' EXIT TERM  # 用钩子,等退出删除锁文件

更新日志 - 重要,会发布已知BUG!

v1

这个是原本给Buildroot用的,详见Milk-V Duo S | 使用报告

v1.1

这个版本对上一版进行进一步美化。

v1.2

这一版通过以下方式优化性能,更适合资源有限的嵌入式设备!

  1. 上一版我使用${date +%T}显示时间戳,这一版直接用\t;
  2. 上一版使用的git分支引用每次调用插入,已改进。

v1.5

让第一行多出了耗时(包括空闲用时)

v1.6

  • 增加了备忘录别名memo(自行在开头备注下设置备忘录路径变量,先去掉开头“#”)
  • 增加了条件判断,如下:
    1. 如果是root用户,用户名变为 红色 警示
    2. 如果 备忘录路径变量,发出提示(在输入memo的时候)

v1.8

  • 增加了类似fish的路径折叠功能。

v2.1

  • 优化类fish路径折叠,即父目录为单字符缩写(隐藏目录为两个字符)
  • 耗时变为复合型,将整条命令的时间记录(即上条提示符命令被执行到这个提示符出现的时间,精确度为1ms)

此版本代码变少,但功能更强了!建议搭配上ble.sh使用,“口感”更加:)

BUG: 空闲时间无法显示,现为换行时间

v2.2

  • 改进v2.1,使耗时的ms.xxxms单位之间加上空格
  • 加上了边框
  • 去掉了错误提示的小括号来适应边框
  • 修改备忘录条件判断选项-e(文件是否为空)改为:-z(变量是否为空)

v2.3

  • 在v2.3的基础上增加了小时的换算
  • 修复原本时间显示紫色括号分割性强的特点,改为白色
  • 更改了ble.sh的启动逻辑,如果需要用ble.sh,建议取消注释(在自定义栏的最下面),因为ble.sh会shell嵌套,所以当$SHLVL=2,自动退出解决问题!

在原来的基础上增加了一个if。此外,过程中发现了一个BUG.

BUG: 在登录shell模式下,无法正常进行计算,但tty和ssh下正常
(原因:正常shell和登录shell的某个变量机制不同,导致原本[命令执行到下一个提示符出现]的时间被迫变为[命令提示符出现到下一个提示符出现]的时间……

v2.5

经过和网友的交流发现上个版本的 BUG 是因为ble.sh插件。

  • 改进了上一版本的bug
  • 在末尾增加了一个欢迎提示,可以安装figlet搭配使用!

v2.6

  • 发现v2.5的figlet有概率触发不了,改用文件锁的方式
  • 增加thefuck命令的if判断,就可以不用自己手动注释了

v2.7

  • 增加了错误判断的表情(挺可爱的)
  • 将横杠改为中文全角破折号

此外,v2.5 BUG重现!除了非登录shell无一幸免

BUG: 在登录shell模式下,无法正常进行时间计算,所有登录shell都一样……也有可能是我的shell问题,因为最近用的是Debian Sid……

v2.8

感谢hllRGB(github)帮我解决了上一版的问题,ta告诉我$PROMPT_COMMAND不是普通变量,而是数组。在原本的$PROMPT_COMMAND上增加了(" ")保证不让shell的配置打架
其次我又在=前面加上了+,成就了魔法?

  • 修复了计时器问题

  • 与ble.sh不太兼容!

    BUG: 在 \(\text{~/.bashrc}\)\(\text{/etc/bash.bashrc}\) 相同的情况下,删除 \(\text{~/.bashrc}\) 会导致计时功能不正确

v2.8.1

  • 修改欢迎界面,加入小猫
  • 更改欢迎界面字体,更具可读性
    如果想要体验,请安装figlet

另外,如果想要修复上一版的 BUG ,请修改 \(\text{~/.profile}\) 中刷新 \(\text{\$HOME/.bashrc}\) 的脚本全部改成 \(\text{/etc/bash.bashrc}\) 即可删除 \(\text{~/.bashrc}\)

posted @ 2025-06-30 11:27  BiaoZyx  阅读(208)  评论(0)    收藏  举报