如何在提示中截断工作目录以显示第一个和最后一个文件夹?

时间:2014-10-24 19:11:45

标签: macos bash prompt

我正在寻找一种实现响应式工作目录的方法,我至少想要显示第一个和最后一个文件夹。 它应该基于终端中的可用。例如。例如$(expr tput cols - 35)}

想象一下当前的工作目录是~/workspace/i/keep/my/projects/project1/src

然后我想显示提示符:

~/workspace/../src

如果终端足够大,我希望:

~/workspace/../project1/src

~/workspace/../projects/project1/src

~/workspace/../my/projects/project1/src

等等。

如果有足够的地方,它甚至应该显示完整的路径。 为了赢得空间,主目录应始终显示为~

这是否可以在OSX上使用纯bash脚本?

2 个答案:

答案 0 :(得分:12)

最简单案例的解决方案

  

我想显示提示,例如:~/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

    这会将当前工作目录打印到stdout

  • "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;}'

代码考虑了这些情况:

  1. 目录字符串已经足够短了。换句话说,它的长度适合分配的空间。在这种情况下,它按原样显示。

  2. 只有三个目录。例如,~/dir1/dir2。我们的格式不允许缩短。因此,对于这种情况,目录字符串按原样显示。

  3. 有四个或更多目录,必须缩短目录字符串以适应空间。在这种情况下,目录字符串被分为存储在变量b中的开头和存储在变量e中的结尾。开头包含两个目录和点 - 点字符串,例如~/dir1/../。从最后一个目录开始,当空间允许时,目录将添加到结束字符串e

  4. 有关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的长度。 en。剩下的e的值是我们剩下的空间量。然后从该行的倒数第二个目录开始,我们尝试一次将一个目录添加到{print b e;},而不会超过目标字符串应该达到的目标。

    • n=0.3*n

      这将打印提示中使用的最终目录字符串。

    全宽显示

    要更改目录显示占用的空间量,我们将读取n=1*n(目标为30%宽度)的命令更改为$(即使是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\$ ' (换行符):

    {{1}}

答案 1 :(得分:0)

我创建了一个基本脚本(仍然需要一些增强功能来完成最后的计算路径,以找出在&#34;〜/ worksapce /../&#之后要显示多少部分(最后部分或后缀部分) ;(fpart或第一部分或前缀),否则,如果您符合以下条件,它将起作用:

1.出口栏目

< strong> 2.设置你的PS1 为&#34; *导出PS1 =&#34;`〜/ somedir / koba.sh` $&#34;

当你的COLUMNS值小于echo ~/workspace | wc -c时,我也测试了〜/ workspace文件夹的条件。此基本示例脚本仅将lpart / suffix / last部分作为最后一个文件夹(因为我使用basename命令)。唯一的另一件事,我看到的是,我每次都必须导出PS1(在最小化/最大化窗口之后,但之后它按预期工作)。


[giga @ someserver somePS1] $ cat~ / somedir / koba.sh

#!/bin/bash

## NOTE this script should echo only 1 echo output and exit out as soon as you echo 
## your first echo.

cdir=`pwd`
wc_dir=$(echo $cdir | wc -c)
bal=$(expr $COLUMNS - $wc_dir)

if [[ "`echo $(pwd) | tr '/' '\012'| wc -l`" -le 2 || $bal -ge $wc_dir ]];
then
 echo "`pwd`"; exit 0 ;
else
 fpart="$(echo $cdir | cut -d'/' -f1,2)/../"
 lpart="$(basename $cdir)"
 ## Calculate lpart (last part) in an better way to show ../aaa or ../aaa/bbb or ../aaa/bbb/c1 or more depending upon $COLUMNS and $wc_dir
 ## Do that math here.
 ## ...
 ## ...

 echo "${fpart}${lpart}"; exit 0;
fi

导出这2个ENV变量后。如果你:

只需将以下ENVIRONMENT变量设置为脚本即可。每次显示PS1之前,此变量都会调用脚本。因此,它设置dir值,PS1设置为以给定格式显示。使用此功能,现在每次更改窗口/屏幕大小时, NOT 都必须重置PS1,或者在路径中移动到不同的父/子文件夹。只需按Enter键(最小化/最大化窗口),看看它有效!!!

export PROMPT_COMMAND="~/somedir/koba.sh"