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

Macos 如何在提示中截断工作目录以显示第一个和最后一个文件夹?,macos,bash,prompt,Macos,Bash,Prompt,我正在寻找一种方法来实现一个响应工作目录,其中至少要显示第一个和最后一个文件夹。 它应基于终端中可用的。例如,类似于$(exprtput cols-35)} 假设当前工作目录是~/workspace/i/keep/my/projects/project1/src 然后我想显示如下提示: ~/workspace/。/src 如果航站楼足够大,我希望: ~/workspace/。/project1/src 或 ~/workspace/./projects/project1/src ~/workspa

我正在寻找一种方法来实现一个响应工作目录,其中至少要显示第一个和最后一个文件夹。 它应基于终端中可用的。例如,类似于
$(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脚本是否可能实现这一点?

对于最简单的情况,解决方案 我想显示如下提示:
~/workspace//src

这将显示该样式的路径,同时以通常的
$
和空格结束提示:

PS1='$(pwd | sed -E -e "s|^$HOME|~|" -e '\''s|^([^/]*/[^/]*/).*(/[^/]*)|\1..\2|'\'') \$ '
虽然我的意图是在OSX的BSD
sed
上进行这项工作,但我只在Linux上使用GNU
sed
对其进行了测试

此版本仅提供一种输出格式。它不会随着终端变宽而改变格式

工作原理 新的
PS1
定义中的关键元素是命令替换。该命令是:

pwd | sed -E -e "s|^$HOME|~|" -e 's|^([^/]*/[^/]*/).*(/[^/]*)|\1..\2|'
  • pwd

    这会将当前工作目录打印到标准输出

  • “s|^$HOME | ~|”

    如果路径以
    $HOME
    开头,请将其替换为
    ~
    。由于
    $HOME
    是一个shell变量,因此该命令必须用双引号引起来,以便shell对
    $HOME
    进行变量替换

  • 的|^([^/]*/[^/]*/).*(/[^/]*)|\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;}'\'') \$ '
守则考虑了以下情况:

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

  • 只有三个目录。例如,
    ~/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)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
      添加一个目录,而不超过di持续多长时间的目标
      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;}'
      
      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;}'\'') \$ '
      
      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\$ '
      
      #!/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
      
      export PROMPT_COMMAND="~/somedir/koba.sh"