基于当前目录字符串长度的命令提示符 (PS1) 的设置值

Setting value of command prompt ( PS1) based on present directory string length

我知道我可以这样做来反映 PS1 值中的最后 2 个目录。

PS1=${PWD#"${PWD%/*/*}/"}#

但是假设我们有一个非常混乱的目录名称,会减少我的工作 space ,比如

T-Mob/2021-07-23--07-48-49_xperia-build-20191119010027#

2021-07-23--07-48-49_nokia-build-20191119010027/T-Mob#

这些是 prompt

之前的最后两个目录

我想设置条件 如果最后两个目录中的任何一个的目录长度超过阈值,例如10 个字符,用长度超过 10 的目录的前 3 个和后 3 个字符缩短名称 例如

    2021-07-23--07-48-49_xperia-build-20191119010027  & 

2021-07-23--07-48-49_nokia-build-20191119010027 

gt 10 都将缩短为 202*027 & PS1 将分别缩短为

T-Mob/202*027/# for T-Mob/2021-07-23--07-48-49_xperia-build-20191119010027#202*027/T-Mob# for 2021-07-23--07-48-49_nokia-build-20191119010027/T-Mob#

一个快速的 1 Liner 来完成这个? 我不能在评论中 post 这个所以在这里更新。参考 Joaquins Answer ( thx J)

PS1=''`echo ${PWD#"${PWD%/*/*}/"} | awk -v RS='/' 'length()  <=10{printf [=15=]"/"}; length()>10{printf "%s*%s/", substr([=15=],1,3),  substr([=15=],length()-2,3)};'| tr -d "\n"; echo "#"`''


见下文o/p的

/root/my-applications/bin # it shortened as expected
my-*ons/bin/#cd -  # going back to prev.
/root
my-*ons/bin/#    #value of prompt is the same but I am in /root

单线基本上总是错误的选择。编写健壮、可读和可维护的代码(并且,对于经常调用或在紧密循环中调用的东西,要高效)——不要简洁。

假设 bash 4.3 或更新版本可用:

# Given a string, a separator, and a max length, shorten any segments that are
# longer than the max length.
shortenLongSegments() {
  local -n destVar=; shift  # arg1: where do we write our result?
  local maxLength=; shift   # arg2: what's the maximum length?
  local IFS=; shift         # arg3: what character do we split into segments on?
  read -r -a allSegments <<<""; shift        # arg4: break into an array

  for segmentIdx in "${!allSegments[@]}"; do   # iterate over array indices
    segment=${allSegments[$segmentIdx]}        # look up value for index
    if (( ${#segment} > maxLength )); then     # value over maxLength chars?
      segment="${segment:0:3}*${segment:${#segment}-3:3}" # build a short version
      allSegments[$segmentIdx]=$segment        # store shortened version in array
    fi
  done
  printf -v destVar '%s\n' "${allSegments[*]}" # build result string from array
}

# function to call from PROMPT_COMMAND to actually build a new PS1
buildNewPs1() {
  # declare our locals to avoid polluting global namespace
  local shorterPath
  # but to cache where we last ran, we need a global; be explicit.
  declare -g buildNewPs1_lastDir
  # do nothing if the directory hasn't changed
  [[ $PWD = "$buildNewPs1_lastDir" ]] && return 0
  shortenLongSegments shorterPath 10 / "$PWD"
  PS1="${shorterPath}$"
  # update the global tracking where we last ran this code
  buildNewPs1_lastDir=$PWD
}

PROMPT_COMMAND=buildNewPs1 # call buildNewPs1 before rendering the prompt

请注意,printf -v destVar %s "valueToStore" 用于就地写入变量,以避免 var=$(someFunction) 的性能开销。类似地,我们正在使用 bash 4.3 功能名称变量——可通过 local -ndeclare -n 访问——允许目标变量名称被参数化而没有 eval 的安全风险.


如果你真的想让这个逻辑只适用于最后两个目录名(虽然我没有看到为什么会比将它应用于所有这些更好),你可以很容易地做到这一点:

buildNewPs1() {
  local pathPrefix pathFinalSegments
  pathPrefix=${PWD%/*/*}           # everything but the last 2 segments
  pathSuffix=${PWD#"$pathPrefix"}  # only the last 2 segments

  # shorten the last 2 segments, store in a separate variable
  shortenLongSegments pathSuffixShortened 10 / "$pathSuffix"

  # combine the unshortened prefix with the shortened suffix
  PS1="${pathPrefix}${pathSuffixShortened}$"
}

...添加仅在目录更改为此版本时重建 PS1 的性能优化留作 reader.

的练习

可能不是最好的解决方案,但是使用 awk 的快速解决方案:

PS1=`echo ${PWD#"${PWD%/*/*}/"} | awk -v RS='/' 'length()<=10{printf [=10=]"/"}; length()>10{printf "%s*%s/", substr([=10=],1,3), substr([=10=],length()-2,3)};'| tr -d "\n"; echo "#"`

我用你的例子得到了这个结果:

T-Mob/202*027/#
202*027/T-Mob/#