如何缩短命令行提示符当前目录?

Posted

技术标签:

【中文标题】如何缩短命令行提示符当前目录?【英文标题】:How can I shortern my command line prompt's current directory? 【发布时间】:2011-08-06 22:39:42 【问题描述】:

我正在使用 Ubuntu,当我处理一些较深的目录层次结构时,我厌倦了 bash 中的这种长提示。所以,我想通过以下方式调整我的 PS1 以缩短工作目录部分:

目前我有:

pajton@dragon:~/workspace/projects/project1/folder1/test$

并且想拥有:

pajton@dragon:~/workspace/.../folder1/test$

如果 len($PWD) 超过给定阈值,则会发生截断。我想始终保留第一个路径组件和至少一个最后一个路径组件。然后在空间允许的情况下,从右侧添加更多组件。

这是我目前拥有的。它可以工作,但是:1)不保留第一个路径组件,2)不尊重边界处的切割路径:

pwd_length=14
pwd_symbol="..."
newPWD="$PWD/#$HOME/~"

if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD="...$(echo -n $PWD | sed -e "s/.*\(.\$pwd_length\\)/\1/")"
else
   newPWD="$(echo -n $PWD)"
fi

结果:

pajton@dragon:...sth/folder1/sample$ 

提前致谢!

【问题讨论】:

另外,您可以在 PS1 中使用换行符 (\n) 将工作目录和实际提示放在不同的行中。 另一种方法是在 PS1 的末尾添加一个换行符,这样您就可以看到整个路径,但您仍然可以键入一个长命令而不用换行。反正我就是这么做的:) (抱歉,@ak2 有重复的评论 - 当我点击“添加评论”时,您的评论不在。) 这也是一个解决方案,但我个人不喜欢两行提示。太冗长了:) +1 提出了一个非常好的问题。我也不喜欢 2 行提示,并且不得不处理包装在深层嵌套目录中的命令。但是现在我已经按照下面的答案设置了我的环境,并且更喜欢它:)。 【参考方案1】:

Raychi 的答案在 Mac / Catalina 上非常适合我。

稍微修改了相应的部分,以获得“两个深度”的开头。

if (length($0) > 16 && NF > 5)
   print $1,$2,$3,".." NF-5 "..",$(NF-1),$NF

结果将类似于:

/Volumes/Work/..3../Python/Tutorials

我的 .bashrc 文件作为一个独立的复制粘贴解决方案的相关部分是:

MYPSDIR_AWK=$(cat << 'EOF'
BEGIN  FS = OFS = "/" 

   sub(ENVIRON["HOME"], "~");
   if (length($0) > 16 && NF > 5)
      print $1,$2,$3,".." NF-5 "..",$(NF-1),$NF
   else
      print $0

EOF
)

export MYPSDIR='$(echo -n "$PWD" | awk "$MYPSDIR_AWK")'

请注意,上述内容不包括 Raychi 的 配色方案。如果需要,请单独添加。

【讨论】:

【参考方案2】:

https://github.com/chrissound/SodiumSierraStrawberry

允许您截断如下路径:

来自: /home/sodium/Projects/Personal/Sierra/Super/Long/Path/HolyAvacado

收件人:»Projects/Sie.../Sup.../Lon.../Pat.../HolyAvacado/

【讨论】:

【参考方案3】:
generatePwd()
  set -- "`pwd | sed -e s.$HOME.~.g`"
  IFS="/"; declare -a array=($*)
  srt=""
  count=0
  for i in $!array[@]; do
      # echo $array[i] - $i/$#array[@]
      if [[ $i == 0 ]]; then
        srt+=""
      elif [[ $i == $(($#array[@]-1)) ]] || [[ $i == $(($#array[@]-2)) ]]; then
          srt+="/$array[i]"
      else
        count=$(($count+1))
      fi
  done
  if [[ $count != 0 ]]; then
    srt="$array[0]/.$count.$srt"
  else
    srt="$array[0]$srt"
  fi
  echo "$srt"

导出 PS1

PS1="\$(generatePwd)"

控制台

$ ~/.3./machine-learning/deep-learning-computer-vision

【讨论】:

【参考方案4】:

另一种方法,仍然使用sedawk 来生成提示。这会将您的 $HOME 目录转换为 ~,显示您的根目录、最低级别(当前目录)及其父目录,中间的每个目录用 .. 分隔。

在您的 .bashrc(或 OS X 上的 .bash_profile)内部:

function generate_pwd 
  pwd | sed s.$HOME.~.g | awk -F"/" '
  BEGIN  ORS="/" 
  END 
  for (i=1; i<= NF; i++) 
      if ((i == 1 && $1 != "") || i == NF-1 || i == NF) 
        print $i
      
      else if (i == 1 && $1 == "") 
        print "/"$2
        i++
      
      else 
        print ".."
      
    
  '

export PS1="\$(generate_pwd) -> "

该脚本使用 awk 内置的NF 变量(字段数)和位置变量($1, $2 ...)来打印由ORS 变量(输出记录分隔符)分隔的每个字段(目录名称)。它会在提示符中将内部目录折叠到 ..

使用示例:

~/ -> cd Documents/
~/Documents/ -> cd scripts/
~/Documents/scripts/ -> cd test1/
~/../scripts/test1/ -> cd test2
~/../../test1/test2/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2
~/../../test1/test2/ -> cd test3/
~/../../../test2/test3/ -> cd test4/
~/../../../../test3/test4/ -> pwd
/Users/Brandon/Documents/scripts/test1/test2/test3/test4
~/../../../../test3/test4/ -> cd /usr/
/usr/ -> cd local/
/usr/local/ -> cd etc/
/usr/local/etc/ -> cd openssl/
/usr/../etc/openssl/ -> cd private/
/usr/../../openssl/private/ ->

【讨论】:

【参考方案5】:

这是我根据 anubhava 的解决方案使用的。它设置提示和窗口标题。 awk 脚本更具可读性,因此可以轻松调整/自定义。

如果路径超过 16 个字符和 4 层深度,它将折叠路径。此外,它还会在...中指示折叠了多少目录,因此您可以了解路径的深度,即:~/usr/..4../path2/path1 表示折叠了 4 个级别。

# define the awk script using heredoc notation for easy modification
MYPSDIR_AWK=$(cat << 'EOF'
BEGIN  FS = OFS = "/" 
 
   sub(ENVIRON["HOME"], "~");
   if (length($0) > 16 && NF > 4)
      print $1,$2,".." NF-4 "..",$(NF-1),$NF
   else
      print $0

EOF
)

# my replacement for \w prompt expansion
export MYPSDIR='$(echo -n "$PWD" | awk "$MYPSDIR_AWK")'

# the fancy colorized prompt: [0 user@host ~]$
# return code is in green, user@host is in bold/white
export PS1='[\[\033[1;32m\]$?\[\033[0;0m\] \[\033[0;1m\]\u@\h\[\033[0;0m\] $(eval "echo $MYPSDIR")]$ '

# set x/ssh window title as well
export PROMPT_COMMAND='echo -ne "\033]0;$USER@$HOSTNAME%%.* $(eval "echo $MYPSDIR")\007"'

这就是它在行动中的样子。绿色的 0 是最后一条命令的返回码:

【讨论】:

【参考方案6】:

与以前的解决方案没有太大区别。但是,也许更具可读性/可编辑性。但是,没有解决文件夹名称边界的问题,只关注提示的长度。

### SET MY PROMPT ###
if [ -n "$PS1" ]; then
    # A temporary variable to contain our prompt command
    NEW_PROMPT_COMMAND='
        pwd_short=$PWD/#$HOME/\~;
        if [ $#pwd_short -gt 53 ]; then
            TRIMMED_PWD=$pwd_short: 0: 25...$pwd_short: -25
        else
            TRIMMED_PWD=$pwd_short
        fi
    '

    # If there's an existing prompt command, let's not 
    # clobber it
    if [ -n "$PROMPT_COMMAND" ]; then
        PROMPT_COMMAND="$PROMPT_COMMAND;$NEW_PROMPT_COMMAND"
    else
        PROMPT_COMMAND="$NEW_PROMPT_COMMAND"
    fi

    # We're done with our temporary variable
    unset NEW_PROMPT_COMMAND

    # Set PS1 with our new variable
    # \h - hostname, \u - username
    PS1='\u@\h: $TRIMMED_PWD\$ '
fi

添加到 .bashrc 文件中。 提示的所有部分都已正确更新。如果您在主目录中,则第一部分会缩短。 示例:

用户@计算机:~/misc/projs/solardrivers...src/com/mycompany/handles$

【讨论】:

【参考方案7】:

为什么不直接使用$string:position:length? 您可以使用$string:-$max_chars 来获得字符串的最后一个$max_chars

注意负值

【讨论】:

这是bash 还是php【参考方案8】:

除了使用PROMPT_DIRTRIM 的bash-builtin 解决方案之外,您可能还想尝试$(pwd | tail -c16),它比大多数其他答案简单一点,但只给出了当前目录的最后16 个字符。当然,用你想要的任何数字替换 16。

【讨论】:

【参考方案9】:

根据您的情况考虑使用 awk 而不是 sed 的脚本:

pwd_length=14
pwd_symbol="..."
newPWD="$PWD/#$HOME/~"
if [ $(echo -n $newPWD | wc -c | tr -d " ") -gt $pwd_length ]
then
   newPWD=$(echo -n $newPWD | awk -F '/' '
   print $1 "/" $2 "/.../" $(NF-1) "/" $(NF)')
fi
PS1='$newPWD$ '

对于您的目录 ~/workspace/projects/project1/folder1/test 示例,它使 PS1 为:~/workspace/.../folder1/test

更新

上述解决方案将设置您的提示,但正如您在评论中指出的那样,当您更改目录时它不会动态更改 PS1。所以这里是当你改变目录时动态设置 PS1 的解决方案。

将这两行放在你的 .bashrc 文件中:

export MYPS='$(echo -n "$PWD/#$HOME/~" | awk -F "/" '"'"'
if (length($0) > 14)  if (NF>4) print $1 "/" $2 "/.../" $(NF-1) "/" $NF;
else if (NF>3) print $1 "/" $2 "/.../" $NF;
else print $1 "/.../" $NF; 
else print $0;'"'"')'
PS1='$(eval "echo $MYPS")$ '

if (NF &gt; 4 &amp;&amp; length($0) &gt; 14) awk 中的条件仅在当前目录深度超过 3 个目录且 $PWD 的长度超过 14 个字符时才应用特殊处理,否则它将保持 PS1 为 $PWD

例如:如果当前目录是~/workspace/projects/project1$,那么 PS1 将是~/workspace/projects/project1$

.bashrc 中的上述效果将在您的 PS1 上如下所示:

~$ cd ~/workspace/projects/project1/folder1/test
~/workspace/.../folder1/test$ cd ..
~/workspace/.../project1/folder1$ cd ..
~/workspace/.../project1$ cd ..
~/.../projects$ cd ..
~/workspace$ cd ..
~$

注意当我更改目录时提示是如何变化的。如果这不是您想要的,请告诉我。

【讨论】:

这很好用!但它始终保留最后两个路径组件。是否可以根据允许的$pwd_length 保留可变数量的最后路径组件?谢谢! 我知道如何更改 PS1 :)。我的意思是:如果$pwd_length 足够大,则路径的两个以上组件可能适合。 IOW 我想知道是否有可能使 PS1 成为 pwd_length 的函数,其行为基于 pwd_length @pajton:我的回答确实考虑了 PS1 格式中的pwd_length&gt;14 条件。请参阅上面的 if (NF &gt; 4 &amp;&amp; length($0) &gt; 14) 条件,其中 14 是您的 $pwd_length 值。但是,由于根据您的原始问题,我使用了 pwd[0]/pwd[1]/.../pwd[n-2]/pwd[n-1] PS1 格式,所以我添加了 1 个子条件来强制执行此 $pwd_length&gt;14 检查,一旦 CWD 至少有 4 级深度。 是的,是的。我的意思是当pwd_length 很大时,如果pwd_length 允许,最好有pwd[0]/pwd[1]/.../pwd[n-k]/&lt;more&gt;/pwd[n-2]/pwd[n-1] 和一些k&gt;2 知道了:要更改最终路径的颜色,您可以将结果用例如左侧的 [\e[0;34m] 和右侧的 [\e[0m]\$ 括起来紫色,所以 PS1='[\e[0;34m] $(eval "echo $MYPS")\[\e[0m\]\$ '【参考方案10】:

对于寻找更简单的解决方案并且不需要路径中第一个目录的名称的人,Bash 使用 PROMPT_DIRTRIM 变量对此提供了内置支持。 From the documentation:

PROMPT_DIRTRIM

如果设置为大于零的数字,则该值用作扩展 \w 和 \W 提示字符串转义时要保留的尾随目录组件的数量(请参阅打印提示)。删除的字符将替换为省略号。

例如:

~$ mkdir -p a/b/c/d/e/f
~$ cd a/b/c/d/e/f
~/a/b/c/d/e/f$ export PROMPT_DIRTRIM=2
~/.../e/f$ PROMPT_DIRTRIM=3
~/.../d/e/f$ 

缺点:这取决于目录级别,而不是您可能不想要的路径长度。

优点:非常简单。只需将export PROMPT_DIRTRIM=2 添加到您的.bashrc

【讨论】:

嗯……这对我在 OSX 上不起作用。我把它放在我的 .bash_profile 中(我认为这在 OSX 上是合适的......它肯定在新的 shell 上执行)并且也尝试过从命令提示符“导出 PROMPT_DIRTRIM=2”。 它不适用于带有 bash 的 OSX,从 Apple 发货(我在 Mountain Lion 上)。发布的版本是 3.2.48(1)-release。如果你使用 Homebrew 之类的东西安装最新的 bash,你会得到 4.2.45(2)-release 附近的东西,它确实支持 PROMPT_DIRTRIM。 是的,这个环境变量是在 bash 4 版本中引入的。 哇,在 2016 年,OS X 仍然随 bash 3.2.57, (c) 2007 一起发布。 @LarsH 因为 bash 3.2 是 GPLv2+ 的最后一个版本。 Bash 4.0+ 是 GPLv3+,Apple 对发布 GPLv3 软件有严格的政策。【参考方案11】:
echo -n $PWD | sed -re "s|(~?/[^/]*/).*(.$pwd_length)|\1...\2|"

sed 和 -r 只是为了方便,允许在括号前省略反斜杠和“|”作为分隔符也只是为了方便 - 因为我们想在命令中使用斜杠。我猜你的 home get 也显示为 ~,所以 ~/foo/bar/baz/ 应该以 ~/foo/.../baz 结尾,而 /foo/bar/baz/ 作为 /foo/.../baz /。

所以我们取一个可选的~,然后是斜杠、名称、斜杠作为\1,然后是一些东西,然后是\2。

【讨论】:

谢谢。它保留第一个路径组件。但是,它不尊重“/”边界:pajton@dragon:~/workspace/...der1/test$ 然后试试这个echo -n $PWD | sed -re "s|(~?/[^/]*/).*(/.14,)|\1...\2|",如果可行的话,用$pwd_length替换14;我会更新我的帖子。

以上是关于如何缩短命令行提示符当前目录?的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio 里一秒打开 命令提示符,并定位到当前仓库的目录

右键在目录当前打开命令行cmd窗口

如何从命令提示符快速打开当前目录?操作系统 - Windows

如何设置linux显示当前目录

通过什么命令指定命令提示符?

如何在当前目录中打开命令提示符作为快捷方式