Bash 提示缩短
Bash prompt shortening
我刚刚从 tcsh
移动到 bash
,我特别错过了使用 %c02
的目录缩短提示选项(同时设置了 ellipsis
)。
我看到 PROMPT_DIRTRIM
几乎做对了(我认为省略号除外)但我只在 bash
3(在 OS X 上)。我发现 this recipe elsewhere on SO,它缩短了总长度,因此在目录中间打断了路径名,这是我不喜欢的。
所以我想到了这个:
PROMPT_DIRTRIM=2 ## from bash4, but used here
dirtrim()
{
local NAME="" start= endelts=
[[ "$NAME" =~ ^"$HOME"(/|$) ]] && NAME="~${NAME#$HOME}" ## $HOME ==> ~
IFS=/ read -ra elts <<< "$NAME"; ## split $PWD on "/"
start=$((${#elts[@]}-${PROMPT_DIRTRIM})) ## first element to retain
if [ ${start} -gt 1 ]; then
for ((i=${start}; i<${#elts[@]}; i++)); do
endelts="${endelts}/${elts[$i]}"; ## concat together the trailing path
done
NAME="...${endelts}"
fi
echo "$NAME"
}
PS1='\h:$(dirtrim "$PWD")$ '
有效:
blackat:~$ cd ~/Library/Application\ Support/Apple
blackat:.../Application Support/Apple$
但我是 bash
的新手,对显式的 for (())
循环不满意;但是,我似乎找不到任何其他方法以正确处理目录名称中的空格的方式重新加入拆分 elts
数组的最后条目(例如,使用 ${elts[@]:${start}}
)。有任何提示或其他改进吗?
(顺便说一句,我认为这是一道编程题,以至于bash
是一门编程语言....)
你可以试试这个:
if ((start > 1)); then
name=$(IFS=/; echo .../"${elts[*]:start}")
# If your terminal is correctly set up for unicode, you can save two character positions:
# name=$(IFS=/; echo …/"${elts[*]:start}")
fi
注意在bash中,在包括((...))
内部和数组下标在内的算术语境中,可以只写变量名;不需要印记。
另一种方法是
if ((start > 1)); then
printf -v name "/%s" "${elts[@]:start}"
name=...$name
fi
另一种解决方案,在 BASH_REMATCH
数组中使用正则表达式捕获而不是拆分和重新连接字符串:
dirtrim () {
local path="";
[[ $path =~ ^"$HOME"(/.*)? ]] && path=~${BASH_REMATCH[1]};
((PROMPT_DIRTRIM)) &&
[[ $path =~ ...*((/[^/]*){$PROMPT_DIRTRIM}) ]] &&
path=…${BASH_REMATCH[1]};
echo "$path"
}
((PROMPT_DIRTRIM))
测试并不完全可靠,因为 bash 在算术上下文中的评估具有特殊性。对于分发,您可能更喜欢 [[ $PROMPT_DIRTRIM =~ ^[1-9][0-9]*$ ]]
不是真正的答案,但您可能想看看 mksh
是如何做到这一点的:
PS1=${| local e=$? (( e )) && REPLY+="$e|" REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)} REPLY+=@${HOSTNAME%%.*}: local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~} local m=${%d} n p=...; (( m > 0 )) || m=${#d} (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p= REPLY+=$p$d return $e }
不幸的是,我相信它使用了一些 bash
中没有的扩展。
另外,既然你要换 shell...你考虑过 fish 吗?
它开箱即用,然后是一些。
我刚刚从 tcsh
移动到 bash
,我特别错过了使用 %c02
的目录缩短提示选项(同时设置了 ellipsis
)。
我看到 PROMPT_DIRTRIM
几乎做对了(我认为省略号除外)但我只在 bash
3(在 OS X 上)。我发现 this recipe elsewhere on SO,它缩短了总长度,因此在目录中间打断了路径名,这是我不喜欢的。
所以我想到了这个:
PROMPT_DIRTRIM=2 ## from bash4, but used here
dirtrim()
{
local NAME="" start= endelts=
[[ "$NAME" =~ ^"$HOME"(/|$) ]] && NAME="~${NAME#$HOME}" ## $HOME ==> ~
IFS=/ read -ra elts <<< "$NAME"; ## split $PWD on "/"
start=$((${#elts[@]}-${PROMPT_DIRTRIM})) ## first element to retain
if [ ${start} -gt 1 ]; then
for ((i=${start}; i<${#elts[@]}; i++)); do
endelts="${endelts}/${elts[$i]}"; ## concat together the trailing path
done
NAME="...${endelts}"
fi
echo "$NAME"
}
PS1='\h:$(dirtrim "$PWD")$ '
有效:
blackat:~$ cd ~/Library/Application\ Support/Apple
blackat:.../Application Support/Apple$
但我是 bash
的新手,对显式的 for (())
循环不满意;但是,我似乎找不到任何其他方法以正确处理目录名称中的空格的方式重新加入拆分 elts
数组的最后条目(例如,使用 ${elts[@]:${start}}
)。有任何提示或其他改进吗?
(顺便说一句,我认为这是一道编程题,以至于bash
是一门编程语言....)
你可以试试这个:
if ((start > 1)); then
name=$(IFS=/; echo .../"${elts[*]:start}")
# If your terminal is correctly set up for unicode, you can save two character positions:
# name=$(IFS=/; echo …/"${elts[*]:start}")
fi
注意在bash中,在包括((...))
内部和数组下标在内的算术语境中,可以只写变量名;不需要印记。
另一种方法是
if ((start > 1)); then
printf -v name "/%s" "${elts[@]:start}"
name=...$name
fi
另一种解决方案,在 BASH_REMATCH
数组中使用正则表达式捕获而不是拆分和重新连接字符串:
dirtrim () {
local path="";
[[ $path =~ ^"$HOME"(/.*)? ]] && path=~${BASH_REMATCH[1]};
((PROMPT_DIRTRIM)) &&
[[ $path =~ ...*((/[^/]*){$PROMPT_DIRTRIM}) ]] &&
path=…${BASH_REMATCH[1]};
echo "$path"
}
((PROMPT_DIRTRIM))
测试并不完全可靠,因为 bash 在算术上下文中的评估具有特殊性。对于分发,您可能更喜欢 [[ $PROMPT_DIRTRIM =~ ^[1-9][0-9]*$ ]]
不是真正的答案,但您可能想看看 mksh
是如何做到这一点的:
PS1=${| local e=$? (( e )) && REPLY+="$e|" REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)} REPLY+=@${HOSTNAME%%.*}: local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~} local m=${%d} n p=...; (( m > 0 )) || m=${#d} (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p= REPLY+=$p$d return $e }
不幸的是,我相信它使用了一些 bash
中没有的扩展。
另外,既然你要换 shell...你考虑过 fish 吗?
它开箱即用,然后是一些。