使用目录树/文件名时的紧凑bash提示


16

在具有Ubuntu 14.04和的系统中bash,我具有PS1以以下内容结尾的变量:

\u@\h:\w\$

因此提示显示为

user@machinename:/home/mydirectory$

但是,有时,当前目录的名称很长,或者它位于内部名称很长的目录中,因此提示看起来像

user@machinename:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name$

这将填充终端中的行,并且光标将移至另一行,这很烦人。

我想获得类似的东西

user@machinename:/home/mydirectory1/...another_long_name$

有没有一种方法可以定义PS1变量来“包装”和“压缩”目录名称,以使其不超过一定数量的字符,从而获得较短的提示?


1
幸运的是,我记得在哪里阅读了如何自定义shell提示符:tldp.org/HOWTO/Bash-Prompt-HOWTO/x783.html感谢Bash Prompt HOWTO的作者Giles Orr及其贡献者。
阻止

另请参见unix.stackexchange.com/a/216871/117549(基于ksh,但类似的想法)
Jeff Schaller

Answers:


16

首先,您可能只想更改\wwith \W。这样,仅打印当前目录的名称,而不打印其完整路径:

terdon@oregano:/home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name $ PS1="\u@\h:\W \$ "
terdon@oregano:my_actual_directory_with_another_long_name $ 

如果目录名称本身太长,那可能还不够。在这种情况下,您可以PROMPT_COMMAND为此使用变量。这是一个特殊的bash变量,其值在显示每个提示之前作为命令执行。因此,如果将其设置为根据当前目录路径的长度设置所需提示的函数,则可以得到想要的效果。例如,将这些行添加到您的~/.bashrc

get_PS1(){
        limit=${1:-20}
        if [[ "${#PWD}" -gt "$limit" ]]; then
                ## Take the first 5 characters of the path
                left="${PWD:0:5}"
                ## ${#PWD} is the length of $PWD. Get the last $limit
                ##  characters of $PWD.
                right="${PWD:$((${#PWD}-$limit)):${#PWD}}"
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] ${left}...${right} \$\[\033[00m\] "
        else
                PS1="\[\033[01;33m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] "
        fi


}
PROMPT_COMMAND=get_PS1

效果如下所示:

terdon@oregano ~ $ cd /home/mydirectory1/second_directory_with_a_too_long_name/my_actual_directory_with_another_long_name
terdon@oregano /home...th_another_long_name $ 

10

添加字符返回是我对此的主要解决方案

因此,我的提示(也包含其他内容,甚至更长)如下所示:

在此处输入图片说明

您会注意到$会以新行的形式返回

我做到了

HOST='\[\033[02;36m\]\h'; HOST=' '$HOST
TIME='\[\033[01;31m\]\t \[\033[01;32m\]'
LOCATION=' \[\033[01;34m\]`pwd | sed "s#\(/[^/]\{1,\}/[^/]\{1,\}/[^/]\{1,\}/\).*\(/[^/]\{1,\}/[^/]\{1,\}\)/\{0,1\}#\1_\2#g"`'
PS1=$TIME$USER$HOST$LOCATION'\n\$ '

请注意,即使在单独的行上,超长目录树(例如

/home/durrantm/Dropbox/96_2013_archive/work/code/ruby__rails 缩短为

/home/durrantm/Dropbox/_/code/ruby__rails

即“最上面的三个目录/ _ /最下面的两个目录”,这通常是我关心的

这将确保该行不会由于目录树的长度而变得太长。如果您始终想要完整的目录树,只需调整LOCATION,即

LOCATION=' \[\033[01;34m\]`pwd`'

有关颜色的更多信息,请访问unix.stackexchange.com/q/124407/10043
Michael Durrant

1
您的提示实际上在$ 哪里?(请参阅。)
G-Man说'Reinstate Monica'18

最后添加\ $,谢谢。这是因为通常我也显示了git分支,但这对于这里来说太详细了
Michael Durrant

1
什么?没有换行符?没有SGR0?
G-Man说'Resstate Monica'18

添加了换行符
Michael Durrant

3

创建〜/ .bash_prompt:

maxlen=36
# set leftlen to zero for printing just the right part of the path
leftlen=19
shortened="..."
# Default PWD
nPWD=${PWD}
if [ ${#nPWD} -gt $maxlen ]; then
  offset=$(( ${#nPWD} - $maxlen + $leftlen ))
  nPWD="${nPWD:0:$leftlen}${shortened}${nPWD:$offset:$maxlen}"
else
  nPWD='\w'
fi
echo "\u@\h:$nPWD\$ "

在我的〜/ .bash_profile中添加:

function prompt_command {
  export PS1=$(~/.bash_prompt)
}
export PROMPT_COMMAND=prompt_command

输出为:

user@machinename:/home/mydirectory1/...another_long_name$

1

不是缩短长路径的解决方案,而是在保持所有路径信息可见的同时获得更好概述的一种便捷方法,是在最后一个字符之前添加换行符。这样,即使路径足够长,光标也总是从同一列开始,但是您的控制台窗口应该足够高,以免滚动得太快。为了更清楚起见,我删除了颜色代码:

murphy@seasonsend:~
$ echo $PS1
\u@\h:\w\n\$
murphy@seasonsend:~
$ 

1

我用它,它绕多行并按缩进的长度缩进,user@host因此它假定当前PS1有效的是' \u@\h:\w$'。它不会截断路径,并且会适应当前的端子宽度。它仅在上分割路径/,因此不会优雅地处理非常长的目录(但它确实保留了用于选择/复制的空间)。这样可以确保您始终至少有20个字符的空间可用于输入。

readonly _PS1="${PS1}" 2>/dev/null

function myprompt()
{
    local IFS
    local nn nb pbits xpwd="" ww=60 len=0 pp='\\w\$ '
    local indent uh="${LOGNAME}@${HOSTNAME//.*/}"

    test -n "$COLUMNS" && let ww=$COLUMNS-20  # may be unset at startup

    PS1="${_PS1}"
    if [ ${#PWD} -ge $ww ]; then
        printf -v indent "%${#uh}s%s" " " "> "  # indent strlen(user@host)

        IFS=/ pbits=( $PWD ); unset IFS
        nb=${#pbits[*]}
        for ((nn=1; nn<nb; nn++)) {
            if [ $(( $len + 1 + ${#pbits[$nn]} )) -gt $ww ]; then
                xpwd="${xpwd}/...\n${indent}..."
                len=0
            fi
            xpwd="${xpwd}/${pbits[$nn]}"
            let len=len+1+${#pbits[$nn]}
        }
        # add another newline+indent if the input space is too tight
        if (( ( ${#uh} + len ) > ww )); then
            printf -v xpwd "${xpwd}\n%${#uh}s" " " 
        fi 
        PS1="${PS1/$pp/$xpwd}$ "    
    fi
}
PROMPT_COMMAND=myprompt

这是通过取出魔术\w(仅\w$与此匹配)PS1并将其替换为$PWD,然后将其包装为普通字符串来实现的。PS1每次从保存在中的原始值重新计算一次_PS1,这意味着“不可见的”转义符也被保留,我完整的原始提示字符串为xtermand粗体提示:

PS1="\[\033]0;\u@\h:\w\007\]\[$(tput bold)\]\u@\h\[$(tput sgr0)\]:\w$ "

最终结果是80列终端:

mr@onomatopoeia:~$ cd /usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/Perf/Trace
mr@onomatopoeia:/usr/src/linux/tools/perf/scripts/perl/Perf-Trace-Util/lib/...
               > .../Perf/Trace$ _

这是从bash-3.2开始printf -v var使用的。由于各种复杂性,将需要对的其他变化进行一些调整PS1

xterm标题栏中的路径既没有包装也没有缩写,可以通过将此处的其他答案之一合并到上述函数中来完成。)


0

或者,在我的.zshrc中,如果像素宽度超过某个宽度,则缩写为每个目录的首字母:

user@machinename:/home/mydirectory1/second_directory
user@machinename:/home/mydirectory1/second_directory/my_actual_directory

变成:

user@machinename:/h/mydirectory1/second_directory
user@machinename:/h/m/s/my_actual_directory

这是执行此操作的zsh函数:

     # get the path
     t=`print -P "%m:%~"`;
     t=`echo $t | sed -r 's/([^:])[^:]*([0-9][0-9]):|([^:])[^:]*([^:]):/\1\2\3\4:/'`;
     oldlen=-1;

     # create 4 buckets of letters by their widths
     t1="${t//[^ijlIFT]}";
     t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
     t3="${t//[^ABEKPSVXYCDHNRUw]}";
     t4="${t//[^GoQMmW]}";

     # keep abbreviating parent directories in the path until under 456 pixels
     while (( ( ( ${#t1} * 150 ) + ( ${#t2} * 178 ) + ( ${#t3} * 190 ) + ( ${#t4} * 201 ) ) > 4560 && ${#t}!=oldlen)) {
       oldlen=${#t};
       t=`echo $t | sed 's/\/\(.\)[^\/][^\/]*\//\/\1\//'`;
       t1="${t//[^ijlIFT]}";
       t2="${t//[ijlIFTGoQMmWABEKPSVXYCDHNRUw]}";
       t3="${t//[^ABEKPSVXYCDHNRUw]}";
       t4="${t//[^GoQMmW]}";
     };

     PS1=$t

我实际上使用它来更新终端标题,以便使用多个选项卡,我可以保持哪个选项卡正确。执行此操作的完整.zshrc是在这里找到

这非常方便,因为它保留了上下文,并且在zsh中,您可以使用同一格式快速制表完整的目录。(例如,键入cd /h/m/s/<tab>将自动完成cd /home/mydirectory1/second_directory


这如何适用于OP提出的关于如何定义PS1提示的问题?
Anthon

为了清楚起见,$ t变为PS1
理查德(Richard)

0

尝试使用 此Python脚本。就像您在问题中所希望的那样,它切断了路径名的各个部分。它还使用仅占一列而不是三列的unicode省略号。

路径的示例输出(给定的限制为30个字符时):

/home/mydir…/second…/my_actua

值得注意的是,此解决方案通过使用正确处理了目录名称中的Unicode wcswidth${#PWD}(其他答案已使用)会严重误判包含UTF-8字符的任何路径的视觉宽度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.