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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5687446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 01:03:59  来源:igfitidea点击:

How can I shortern my command line prompt's current directory?

bashstringpathps1

提问by pajton

I am using Ubuntu and I am tired of this long prompts in bash when I am working with some deep directory hierarchy. So, I would like to tweak my PS1 to shorten the working directory part the following way:

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

Currently I have:

目前我有:

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

and would like to have:

并希望拥有:

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

The truncating would occur if len($PWD) passes given threshold. I want to always keep the first path component and at least one last path component. Then as space permits, add more components taking from the right.

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

This is what I have currently. It works, but: 1) doesn't keep first path component, 2) doesn't respect cutting path at boundaries:

这就是我目前所拥有的。它有效,但是: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\}\)//")"
else
   newPWD="$(echo -n $PWD)"
fi

And the result:

结果:

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

Thanks in advance!

提前致谢!

采纳答案by anubhava

Consider this script using awk instead of sed for your case:

对于您的情况,请考虑使用 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  "/"  "/.../" $(NF-1) "/" $(NF)}')
fi
PS1='${newPWD}$ '

For your example of directory ~/workspace/projects/project1/folder1/testit makes PS1 as: ~/workspace/.../folder1/test

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

UPDATE

更新

Above solution will set your prompt but as you noted in your comment that it will NOT change PS1 dynamically when you change directory. So here is the solution that will dynamically set PS1 when you change directories around.

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

Put these 2 lines in your .bashrc file:

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

export MYPS='$(echo -n "${PWD/#$HOME/~}" | awk -F "/" '"'"'{
if (length(
~$ cd ~/workspace/projects/project1/folder1/test
~/workspace/.../folder1/test$ cd ..
~/workspace/.../project1/folder1$ cd ..
~/workspace/.../project1$ cd ..
~/.../projects$ cd ..
~/workspace$ cd ..
~$
) > 14) { if (NF>4) print "/" "/.../" $(NF-1) "/" $NF; else if (NF>3) print "/" "/.../" $NF; else print "/.../" $NF; } else print
~$ 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$ 
;}'"'"')' PS1='$(eval "echo ${MYPS}")$ '

if (NF > 4 && length($0) > 14)condition in awk will only apply special handling when your current directory is more than 3 directories deep AND if length of $PWDis more than 14 characters otherwise and it will keep PS1 as $PWD.

if (NF > 4 && length($0) > 14)awk 中的条件只会在当前目录深度超过 3 个目录时应用特殊处理,否则如果长度$PWD超过 14 个字符,它将保持 PS1 为$PWD.

eg: if current directory is ~/workspace/projects/project1$then PS1 will be ~/workspace/projects/project1$

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

Effect of above in .bashrc will be as follows on your PS1:

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

# define the awk script using heredoc notation for easy modification
MYPSDIR_AWK=$(cat << 'EOF'
BEGIN { FS = OFS = "/" }
{ 
   sub(ENVIRON["HOME"], "~");
   if (length(
echo -n $PWD | sed -re "s|(~?/[^/]*/).*(.{$pwd_length})|...|"
) > 16 && NF > 4) print ,,".." NF-4 "..",$(NF-1),$NF else print
function generate_pwd {
  pwd | sed s.$HOME.~.g | awk -F"/" '
  BEGIN { ORS="/" }
  END {
  for (i=1; i<= NF; i++) {
      if ((i == 1 &&  != "") || i == NF-1 || i == NF) {
        print $i
      }
      else if (i == 1 &&  == "") {
        print "/"
        i++
      }
      else {
        print ".."
      }
    }
  }'
}
export PS1="$(generate_pwd) -> "
} 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='[\[3[1;32m\]$?\[3[0;0m\] \[3[0;1m\]\u@\h\[3[0;0m\] $(eval "echo ${MYPSDIR}")]$ ' # set x/ssh window title as well export PROMPT_COMMAND='echo -ne "3]0;${USER}@${HOSTNAME%%.*} $(eval "echo ${MYPSDIR}")
~/ -> 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/ ->
7"'

Notice how prompt is changing when I change directories. Let me know if this is not what you wanted.

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

回答by imgx64

For people looking for a much simpler solution and don't need the name of the first directory in the path, Bash has built-in support for this using the PROMPT_DIRTRIMvariable. From the documentation:

对于寻找更简单的解决方案并且不需要路径中第一个目录的名称的人来说,Bash 使用PROMPT_DIRTRIM变量内置了对此的支持。从文档

PROMPT_DIRTRIM

If set to a number greater than zero, the value is used as the number of trailing directory components to retain when expanding the \w and \W prompt string escapes (see Printing a Prompt). Characters removed are replaced with an ellipsis.

PROMPT_DITRIM

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

For example:

例如:

### 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

Downside: It depends on the directory level, not the length of the path, which you might not want.

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

Upside: It's very simple. Just add export PROMPT_DIRTRIM=2to your .bashrc.

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

回答by raychi

This is what I use based on the solutions from anubhava. It sets both the prompt and the windows title. The awk script is more readable so it can be tweaked/customized easily.

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

It will fold the path if it's more than 16 chars and 4 levels deep. Furthermore, it will also indicate in the ... how many directories were folded, so you get a sense of how deep the path is, ie: ~/usr/..4../path2/path1indicates 4 levels were folded.

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

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}"
}

Here's what it looks like in action. The green 0 is the return code of last command:

这是它的实际运行情况。绿色的 0 是最后一条命令的返回码:

enter image description here

在此处输入图片说明

回答by user unknown

PS1="$(generatePwd)"

sed with -r only for convenience, allows to omit backslash before parentheses, and "|" as delimiter only for convenience too - because we want to use the slash inside the command. I guess your home get's displayed as ~ as well, so ~/foo/bar/baz/ should end in ~/foo/.../baz, and /foo/bar/baz/ as /foo/.../baz/.

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

So we take an optional ~, followed by slash, name, slash as \1, then something, then the rest as \2.

所以我们取一个可选的~,然后是斜杠,名称,斜杠是\1,然后是something,然后是\2。

回答by Brandon

Another approach, still using sedand awkto generate the prompt. This will convert your $HOMEdirectory into ~, show you your root directory, your lowest level (current directory), and its parent, separated by ..for each directory in between.

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

Inside of your .bashrc(or .bash_profileon OS X):

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

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

The script uses awk's built in NFvariable (number of fields) and positional variables ($1, $2 ...) to print each field (directory name) separated by the ORSvariable (output record separator). It collapses the inner directories into ..in your prompt.

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

Example of it in use:

它的使用示例:

##代码##

回答by Sebastian Mach

Apart from the bash-builtin solution using PROMPT_DIRTRIM, you may want to try $(pwd | tail -c16), which is a tad simpler than most other answers, but just gives the last 16 characters of the current directory. Of course replace 16 by any number you want.

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

回答by Naus Caligo

Why not just use ${string:position:length}? You can do ${string:-$max_chars}to have the last ${max_chars}of the string.

为什么不直接使用${string:position:length}?你可以做${string:-$max_chars}最后一个${max_chars}字符串。

note the negative value

注意负值

回答by karnbo

Not so different from previous solutions. However, maybe a bit more readable/editable. However, no solution to the folder name boundary, only focusing on the length of the prompt.

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

##代码##

added to the .bashrc file. All parts of the prompt is updated properly. The first part is shortened if you're in your home directory. Example:

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

user@computer: ~/misc/projs/solardrivers...src/com/mycompany/handles$

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

回答by matias ezequiel marani

##代码##

export PS1

导出 PS1

##代码##

Console

安慰

##代码##

回答by Chris Stryczynski

https://github.com/chrissound/SodiumSierraStrawberry

https://github.com/chrissound/SodiumSierraStrawberry

Allows you to truncate a path like:

允许您截断路径,如:

From: /home/sodium/Projects/Personal/Sierra/Super/Long/Path/HolyAvacado

To: ?Projects/Sie…/Sup…/Lon…/Pat…/HolyAvacado/

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

至:?项目/Sie.../Sup.../Lon.../Pat.../HolyAvacado/