Search code examples
linuxbashps1

The \w in PS1 cannot deal as string?


I want a color splited path in PS1. I write this function in .bashrc. enter image description here

    colorize_dir_path() {
        #local path=$(echo "$PWD" | perl -pe "s|$HOME|~|")
        #local path="~/project/at-gui/src"
        local path=$1
        local colored_path=""
        local color_array=(27 130 28 133)
        local index=0
        IFS='/' read -ra ADDR <<< $path
        for i in "${ADDR[@]}"; do
            if [ "$i" != "" ]; then
                local color=${color_array[$index]}
                ((index=(index+1)%${#color_array[@]}))
                colored_path+="\e[48;5;${color}m $i "
            fi
        done
        echo -e "\e[37m${colored_path}➽\e[0m"   #白色前景
    }

and set PS1.

PS1="$psc1 \D{%F %A %T} $pgap$(colorize_dir_path "\w")\n$psch "
#PS1="$psc1 \D{%F %A %T} $pgap$(colorize_dir_path "$PWD")\n$psch "
#PS1="$psc1 \D{%F %A %T} $pgap$(colorize_dir_path "$(pwd)")\n$psch "
#PS1="$psc1 \D{%F %A %T} $pgap$(bash ~/bin/ps1.bash "\w")\n$psch "

But the \w can not split into the ADDR array, I only got the entire path. seems it is not a string. How to solve this? pls help. enter image description here


Solution

  • PS1="$psc1 \D{%F %A %T} $pgap$(colorize_dir_path "\w")\n$psch "
    

    Expands all parameters at assignment time, including the command substitution. This means that PS1 is assigned a constant value and \w does not have special meaning outside of PS1; it is only expanded by your shell when rendering the prompt string.

    Try this instead to make the command substitution only be expanded when your prompt string is rendered (note the single quotes):

    PS1="$psc1 \D{%F %A %T} $pgap"'$(colorize_dir_path "\w")'"\n$psch "
    

    The time of evaluation/expansion is easy to verify yourself:

    PS1="$(date):\w\$ "
    echo "$PS1" # prints: Fr 28 Jun 2024 11:40:44 CEST:\w$
    

    and the time displayed in your prompt is constant and never changes. Compare to:

    PS1='$(date):\w\$ '
    echo "$PS1" # prints: $(date):\w\$ 
    

    and every time your prompt string is rendered, it will be evaluated and the current date and time printed next to your current working directory.

    A similar test:

    PS1="$(echo '\w'>&2)\$ "
    

    will print \w to stderr exactly once when assigning the variable. However

    PS1='$(echo "\w">&2)\$ '
    

    prints the path of your current working directory to stderr every time your prompt is rendered.