最简单情况的解决方案
我想显示如下提示:~/workspace/../src
这将显示该样式的路径,同时以通常的$ 和空格结束提示:
PS1='$(pwd | sed -E -e "s|^$HOME|~|" -e '\''s|^([^/]*/[^/]*/).*(/[^/]*)|\1..\2|'\'') \$ '
虽然我的意图是在 OSX 的 BSD sed 上进行这项工作,但我只在带有 GNU sed 的 Linux 上对其进行了测试。
此版本仅提供一种输出格式。它不会随着终端变宽而改变格式。
工作原理
新PS1 定义中的关键元素是命令替换。该命令是:
pwd | sed -E -e "s|^$HOME|~|" -e 's|^([^/]*/[^/]*/).*(/[^/]*)|\1..\2|'
-
pwd
这会将当前工作目录打印到标准输出
-
"s|^$HOME|~|"
如果路径以$HOME 开头,请将其替换为~。因为$HOME 是一个shell 变量,所以这个命令必须用双引号括起来,以便shell 对$HOME 进行变量替换。
-
's|^([^/]*/[^/]*/).*(/[^/]*)|\1..\2|'
正则表达式由三部分组成:
^([^/]*/[^/]*/)匹配前两个目录并保存在\1中。
.* 这匹配前两个目录直到最后一个目录之后的任何内容
(/[^/]*)匹配最后一个子目录并保存在\2中。
如果有足够的目录供正则表达式匹配,则将整个路径替换为\1..\2。
更复杂的解决方案
假设我们希望提示的格式随着终端的可用宽度而变化,如果有空间可以显示更多的最终目录。因此,在窄终端中,/home/user/dir1/dir2/dir3/dir4 可能显示为 ~/dir1/../dir4,但在更宽的终端中,它会显示为 ~/dir1/../dir3/dir4,而在更宽的终端中,它会显示为 ~/dir1/dir2/dir3/dir4。
在这种情况下:
PS1='$(pwd|awk -F/ -v "n=$(tput cols)" -v "h=^$HOME" '\''{sub(h,"~");n=0.3*n;b=$1"/"$2} length($0)<=n || NF==3 {print;next;} NF>3{b=b"/../"; e=$NF; n-=length(b $NF); for (i=NF-1;i>3 && n>length(e)+1;i--) e=$i"/"e;} {print b e;}'\'') \$ '
因为这个解决方案需要更多的计算,所以使用awk。
此代码允许用户调整目录列表应占用多少终端宽度。这是通过调整代码n=0.3*n 中的常量来完成的。如前所述,如果可能,这会将目录显示限制为仅终端宽度的 30%。
工作原理
代码的关键元素是这个命令:
pwd | awk -F/ -v "n=$(tput cols)" -v "h=^$HOME" '{sub(h,"~");n=0.3*n;b=$1"/"$2} length($0)<=n || NF==3 {print;next;} NF>3{b=b"/../"; e=$NF; n-=length(b $NF); for (i=NF-1;i>3 && n>length(e)+1;i--) e=$i"/"e;} {print b e;}'
代码考虑了这些情况:
目录字符串已经足够短了。换句话说,它的长度适合分配的空间。在这种情况下,它会按原样显示。
只有三个目录。例如,~/dir1/dir2。我们的格式不允许缩短。因此,对于这种情况,目录字符串按原样显示。
有四个或更多目录,必须缩短目录字符串以适应空间。在这种情况下,目录字符串分为开头,存储在变量b 和结尾,存储在变量e 中。开头包含两个目录和点点字符串,例如~/dir1/../。从最后一个目录开始,在空间允许的情况下,将目录添加到结尾字符串e。
有关awk 命令的更多详细信息
-
-F/
这会将字段分隔符设置为/。因此,每个目录都将显示为一个单独的字段。
-
-v "n=$(tput cols)" -v "h=^$HOME"
这会创建我们需要的两个变量。 n 具有以列为单位的终端宽度。 h 有一个匹配用户主目录的正则表达式。
-
sub(h,"~")
如果路径以用户的主目录开头,则将其替换为~。
-
n=0.3*n
这为提示中目录字符串的所需宽度设置了一个目标。我喜欢目录字符串不要太长,所以n=0.3*n 将目标设置为列中终端宽度的 30%。正如其他地方所讨论的,这可以根据您的个人喜好替换为另一个公式。
-
b=$1"/"$2
b 是包含目录字符串开头的变量。在这里,我们将其设置为前两个目录。例如,如果路径是~/dir1/dir2/dir3,那么这会将b 设置为~/dir1。
-
length($0)<=n || NF==3 {print;next;}
如果完整的目录字符串不长于我们的目标n,或者如果目录字符串中只有三个目录,则原样打印目录字符串然后退出。
-
NF>3{b=b"/../"; e=$NF; n-=length(b $NF); for (i=NF-1;i>3 && n>length(e)+1;i--) e=$i"/"e;}
如果我们得到,那么我们的目录字符串需要被缩短。因此,我们将缩写字符串/../ 添加到b 的末尾。对于第一次试用,我们将结束字符串 e 设置为最后一个目录。 (在awk 中,NF 是字段数。因此,$NF 是行中的最后一个字段(目录)。)然后我们从n 中减去b 和e 的长度。剩余的n 的值是我们剩余的空间量。然后从该行的倒数第二个目录开始,我们尝试一次将一个目录添加到e,而不超出我们的目标,即目录字符串应该有多长。
-
{print b e;}
这将打印提示中使用的最终目录字符串。
全宽显示
要更改目录显示占用的空间量,我们将读取 n=0.3*n(目标为 30% 宽度)的命令更改为 n=1*n(目标为全宽,即使 $ 提示符溢出到下一行):
PS1='$(pwd|awk -F/ -v "n=$(tput cols)" -v "h=^$HOME" '\''{sub(h,"~");n=1*n;b=$1"/"$2} length($0)<=n || NF==3 {print;next;} NF>3{b=b"/../"; e=$NF; n-=length(b $NF); for (i=NF-1;i>3 && n>length(e)+1;i--) e=$i"/"e;} {print b e;}'\'') \$ '
根据您的喜好,您可能需要其他公式。例如,尝试n=n-10,它会尝试在提示符末尾为您保留一些(但不是很多)可用空间。
PM2Ring 建议始终将$ 提示符放在下一行,为此,我们在\$ 提示符之前放置一个\n(换行符):
PS1='$(pwd|awk -F/ -v "n=$(tput cols)" -v "h=^$HOME" '\''{sub(h,"~");n=1*n;b=$1"/"$2} length($0)<=n || NF==3 {print;next;} NF>3{b=b"/../"; e=$NF; n-=length(b $NF); for (i=NF-1;i>3 && n>length(e)+1;i--) e=$i"/"e;} {print b e;}'\'') \n\$ '