我正在尝试使用 ${VAR//search/replace} 参数扩展对变量进行一些搜索和替换。我有一个又长又邪恶的PS1,我想计算出扩展后的大小。为此,我必须删除填充到其中的一堆转义序列。然而,在尝试删除所有 ANSI CSI SGR 序列时,我遇到了语法问题。
鉴于我的 PS1:
PS1=\[\033]0;[\h] \w\007\]\[\033[1m\]\[\033[37m\](\[\033[m\]\[\033[35m\]\u@\[\033[m
\]\[\033[32m\]\h\[\033[1m\]\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m
\]\t\[\033[37m\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\[\033[36m\]\w\[\033[1m
\]\[\033[37m\])\[\033[35m\]${git_branch}\[\033[m\]\n$
(是的,我知道这很病......)
我正在尝试做:
# readability
search='\\\[\\033\[[0-9]*m\\\]'
# do the magic
sane="${PS1//$search/}"
然而,这些似乎是贪婪的[0-9]
(几乎就像[0-9]
被视为.
相反):
echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\n$
如果我删除*
, 并更改[0-9]
为[0-9][0-9]
(因为这更具说明性),我会更接近预期结果:
$ search='\\\[\\033\[[0-9][0-9]m\\\]'
$ echo "${PS1//$search/}"
\[\033]0;[\h] \w\007\]\[\033[1m\](\[\033[m\]\u@\[\033[m\]\h\[\033[1m
\]\[\033[1m\])\[\033[m\]-\[\033[1m\](\[\033[m\]\t\[\033[1m\])\[\033[m\]-\[\033[1m
\](\[\033[m\]\w\[\033[1m\])$(git_branch)\[\033[m\]\n$
为什么*
(零个或多个)做疯狂的事情?我在这里错过了什么吗?如果我通过 sed 传递相同的正则表达式,我会得到预期的结果:
echo $PS1 | sed "s/$search//g"
\[\033]0;[\h] \w\007\](\u@\h)-(\t)-(\w)$(git_branch)\n$
答案1
在我看来,你想删除\[
和之间的东西\]
:
$ shopt -s extglob
$ printf '%s\n' "${PS1//\\\[*(\\[^]]|[^\\])\\\]/}"
(\u@\h)-(\t)-(\w)${git_branch}\n$
然而,bash
替换效率非常低,因此您可能最好在此处解雇perl
或sed
,或者在循环中执行此操作,如下所示:
p=$PS1 np=
while :; do
case $p in
(*\\\[*\\\]*) np=$np${p%%\\\[*};p=${p#*\\\]};;
(*) break;;
esac
done
np=$np$p
printf '%s\n' "$np"
(顺便说一句,这是上面的标准 POSIX sh 语法)。
如果你想要扩大提示:
ep=$(PS4=$np;exec 2>&1;set -x;:); ep=${ep%:}
答案2
经过 jordanm 的一些指导(以及阅读 bash 手册页的“模式匹配”部分),事实证明参数扩展使用的这些模式不是正则表达式。但是对于我的具体情况,如果shopt extglob
打开,我可以这样做:
search='\\\[\\033\[*([0-9])m\\\]'
其中*([0-9])
与正则表达式中的相同[0-9]*
。
看来 extglob 提供了一些类似于正则表达式的机制(来自 bash 手册页):
?(pattern-list)
Matches zero or one occurrence of the given patterns
*(pattern-list)
Matches zero or more occurrences of the given patterns
+(pattern-list)
Matches one or more occurrences of the given patterns
@(pattern-list)
Matches one of the given patterns
!(pattern-list)
Matches anything except one of the given patterns
答案3
支持 Pure Bash 全系列 ANSI 序列
# Strips ANSI CSI (ECMA-48, ISO 6429) codes from text
# Param:
# 1: The text
# Return:
# &1: The ANSI stripped text
strip_ansi() {
shopt -s extglob
printf %s "${1//$'\e'[@A-Z\[\\\]\^_]*([0-9:;<=>?])*([ \!\"#$%&\'()\^*+,\-.\/])[@A-Z\[\\\]\^_\`a-z\{|\}~]/}"
}